Only this pageAll pages
Powered by GitBook
1 of 27

Tarmac

Loading...

Functions

Loading...

Writing Functions

Loading...

Loading...

Loading...

Capabilities

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Running Tarmac

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

WebAssembly Developer Resources

Rust

Creating a WASM Function in Rust.

Web Assembly (WASM) support is a first-class feature in Rust, making Rust an excellent language to write WASM functions for Tarmac.

This guide will walk users through creating a WASM function for Tarmac in the Rust language. This walkthrough assumes there is some familiarity with the Rust tooling and language to start.

Creating the WASM Function

We will need to begin with a new project folder, creating the src/ directory. Within that directory, we will make our main.rs file.

fn main() {}

Tarmac internally uses a Web Assembly Procedure Calls (waPC) runtime, which means all WASM functions running within Tarmac must import and use a waPC compliant library.

extern crate wapc_guest as guest;
use guest::prelude::*;

fn main() {}

#[no_mangle]
pub extern "C" fn wapc_init() {}

Along with the waPC imports, you should also see a wapc_init() function created. This function is the primary entry point for Tarmac execution. We will register our handler function for Tarmac to execute using the register_function() function within this function.

#[no_mangle]
pub extern "C" fn wapc_init() {
  register_function("handler", handler);
}

In the example above, we have registered the handler() function. When Tarmac receives an HTTP POST request for this WASM function, it will execute the handler function as defined.

With our handler function now registered, we must create a basic version of this handler for Tarmac to call.

fn handler(msg: &[u8]) -> CallResult {}

As we can see from the example above, the handler input a slice of 8-bit unsigned integers, which is the raw HTTP payload. And a return value of CallResult.

Adding Logic

Now that we have the basic structure of our WASM function created, we can start adding logic to the function and process our request.

Host Callbacks

One of the unique benefits of Tarmac is the ability for WASM functions to perform host callbacks to the Tarmac service itself. These Host Callbacks give users the ability to execute common framework code provided to the WASM function by Tarmac. These common framework functions can include storing data within a database, calling a remote API, or logging data.

For our example, we will use the Host Callbacks to create a Trace log entry.

  // Perform a host callback to log the incoming request
  let _res = host_call("tarmac", "logger", "trace", &msg.to_vec());

For a full list of Host Callbacks checkout the Callbacks documentation.

Do Work and Generate a Response

We can add our logic to the example, which in this case will just return the input payload.

  Ok(msg.to_vec())

Full WASM function

For quick reference, the below code is the full WASM function from this example.

// Echo is a small, simple Rust program that is an example WASM module for Tarmac.
// This program will accept a Tarmac server request, log it, and echo back the payload.
extern crate wapc_guest as guest;
use guest::prelude::*;

fn main() {}

#[no_mangle]
pub extern "C" fn wapc_init() {
  register_function("handler", handler);
}

fn handler(msg: &[u8]) -> CallResult {
  // Perform a host callback to log the incoming request
  let _res = host_call("tarmac", "logger", "trace", &msg.to_vec());
  Ok(msg.to_vec())
}

Building the WASM Function

Now that our function is ready, we must compile our Rust code into a .wasm file. To do this, we will need to create our Cargo manifest and build the project.

$ cargo init

Within the Cargo.toml file, we must specify the different packages used in our WASM function.

[package]
name = "echo"
version = "0.1.0"
authors = ["Example Developer <developer@example.com>"]
edition = "2018"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
wapc-guest = "0.4.0"
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
base64 = "0.13.0"

With our manifest defined, we can now build our module.

$ cargo build --target wasm32-unknown-unknown --release

After the code build completes, we will copy the .wasm file into a directory Tarmac can use to run.

$ mkdir -p functions
$ cp target/wasm32-unknown-unknown/release/echo.wasm functions/tarmac.wasm

Running the WASM Function

We are now ready to run our WASM function via Tarmac. To make this process easier, we will be using Docker to execute Tarmac. It is not necessary to use Docker with Tarmac as it can run outside of Docker as well.

$ docker run -p 8080:8080 \
  -e "APP_ENABLE_TLS=false" -e "APP_LISTEN_ADDR=0.0.0.0:8080" \
  -v ./functions:/functions madflojo/tarmac

In the above command, we pass two environment variables to the container using the -e flag. These environment variables will tell Tarmac to use HTTP rather than HTTPS, which is the default. For additional configuration options, check out the Configuration documentation.

With Tarmac now running, we can access our WASM function using any HTTP Client such as curl.

$ curl -v --data "Tarmac Example" http://localhost:8080

Conclusion

Developers can use this guide to get started with WASM functions and using Tarmac. Some of the information in this guide is subject to change as WASM advances. However, the concepts should stay pretty consistent.

Callbacks

Powered by Web Assembly Procedure Calls

Tarmac, at its core, is powered by the Web Assembly Procedure Call (waPC) Project. The Web Assembly Procedure Call Project defines imported and exported functions between a WASM host and a guest WASM function. A WASM runtime host like Tarmac and a WASM Function running within Tarmac can communicate back and forth using these functions.

A prime example of this is the HostCall() function used by guest WASM functions. This HostCall() is a callback function that enables WASM functions to pass back data to the Tarmac host for the explicit goal of executing host-level functionality.

This ability to perform a Host Callback is what sets Tarmac apart from most other serverless runtimes. A WASM function can use the Host Callback functionality to access a full suite of standard functionality that would traditionally be too heavy for a serverless function.

Essentially, Host Callbacks allow Tarmac to provide developers the functionality of a standard Microservice Framework along with the convenience of a serverless runtime.

Using Host Callbacks

Calling a Host Callback is relatively straightforward for WASM functions. As outlined in the language guides, each WASM function must import a waPC compliant guest library. This guest library will allow users to access a HostCall() function for their language of choice.

The example below is an example of calling the Host Callback function in Go.

_, err := wapc.HostCall("tarmac", "logger", "debug", payload)

The HostCall() function takes three parameters. The first is the namespace which developers should always set to tarmac. The second is the capability requested, such as logger or kvstore. The third is the function to execute; for a kvstore capability, we may want to perform a get or a set.

This section of documentation outlines all of the various host-level capabilities Tarmac provides. Each unit will outline the capabilities, functions, and input/output data.

Supported Languages

What languages are known to work with Tarmac.

Currently, Tarmac leverages the Web Assembly Procedure Call (waPC) to interact and run WASM Functions. As such, Tarmac is limited to languages that support both Web Assembly and the waPC protocol.

The below table outlines languages that are fully supported.

Language
waPC Guest Library
Caveats

AssemblyScript

Go

Rust

Swift

Zig

https://github.com/wapc/as-guest
https://github.com/wapc/wapc-guest-tinygo
https://github.com/wapc/wapc-guest-rust
https://github.com/wapc/wapc-guest-swift
https://github.com/wapc/wapc-guest-zig

Multi-Function Services

Configure multi-function services as well as multi-service instances.

Configuring Multi-Function Services is a core capability of Tarmac. To do so, we will create a tarmac.json file that defines Functions and Routes to expose those functions.

By default, Tarmac looks within the /functions/ directory for a tarmac.json; however this can be overridden using the WASM_FUNCTION_CONFIG configuration parameter.

The tarmac.json file has a simple structure that consists of a single object with a services key. The services key defines each service and its corresponding functions and routes.

{
  "services": {
    "my-service": {
      "name": "my-service",
      "functions": {
        "function1": {
          "filepath": "/path/to/function1.wasm",
          "pool_size": 10
        },
        "function2": {
          "filepath": "/path/to/function2.wasm"
        }
      },
      "routes": [
        {
          "type": "http",
          "path": "/function1",
          "methods": ["GET"],
          "function": "function1"
        },
        {
          "type": "http",
          "path": "/function2",
          "methods": ["POST"],
          "function": "function2"
        }
      ]
    }
  }
}

Configuration Options

Services

The services object contains one or more key-value pairs, with each key representing the name of a service.

Each service object should include the following properties:

  • name: The name of the service (required).

  • functions: An object containing the functions for the service (required).

  • routes: An array of objects defining the routes for the service (required).

Functions

The functions object contains one or more key-value pairs, with each key representing the name of a function.

Each function object should include the following properties:

  • filepath: The file path to the .wasm file containing the function code (required).

  • pool_size: The number of instances of the function to create (optional). Defaults to 100.

Routes

The "routes" property in the tarmac.json configuration file defines the endpoints (HTTP or scheduled task) of the service and maps them to their respective functions.

HTTP Routes

The routes array in the tarmac.json configuration file defines the HTTP endpoints for your service.

Each route object contains the following properties:

  • type (required): For HTTP routes, set this to http.

  • path (required): The URL path for the endpoint.

  • methods (required): An array of HTTP methods that the endpoint supports (i.e. GET, POST, PUT, DELETE).

  • function (required): The function to call when the endpoint receives requests.

Here is an example of a route object that defines an HTTP endpoint that responds to GET requests on the root path and calls the default function:

{
  "type": "http",
  "path": "/",
  "methods": ["GET"],
  "function": "default"
}

You can define multiple HTTP routes in the routes array.

Scheduled Tasks

In addition to HTTP endpoints, Tarmac also supports scheduled tasks.

You can define a scheduled task route by adding a route object with the following properties to the routes array:

  • type (required): For Schedule Tasks, set to scheduled_task.

  • function (required): The function to call when the task is executed.

  • frequency (required): The frequency in seconds to execute the function.

Here is an example of a route object that defines a scheduled task that executes the default function every 15 seconds:

{
  "type": "scheduled_task",
  "function": "default",
  "frequency": 15
}

You can define multiple scheduled tasks in the routes array.

Init Functions

In addition to HTTP and scheduled task routes, Tarmac also supports init functions.

You can define an init function route by adding a route object with the following properties to the routes array:

  • type (required): For Init Functions, set to init.

  • function (required): The function to call when the service is initialized.

  • retries (optional): The number of times to retry the function if it fails. Defaults to 0.

  • frequency (optional): The frequency in seconds to retry the function if it fails. Exponential backoff is used. Defaults to 1.

Here is an example of a route object that defines an init function that executes the default function when the service is initialized:

{
  "type": "init",
  "function": "default"
}

You can define multiple init functions in the routes array. Functions will be executed before the server is fully started but after the WASM modules are loaded and callbacks are registered.

Functions

Tarmac supports the ability for Functions to call other Functions using the Function to Function route.

You can define a function route by adding a route object with the following properties to the route array.

  • type (required): For Function to Function routes, set to function.

  • function (required): The function to call when executed.

Here is an example of a route object that defines the "function1" function.

{
  "type": "function",
  "function": "function1"
}

Introduction

Tarmac Banner

Framework for writing functions, microservices, or monoliths with Web Assembly

Tarmac is a new approach to application frameworks. Tarmac is language agnostic and offers built-in support for key/value stores like BoltDB, Redis, and Cassandra, traditional SQL databases like MySQL and Postgres, and fundamental capabilities like mutual TLS authentication and observability.

Supporting languages like Go, Rust, & Zig, you can focus on writing your functions in whatever language you like while benefiting from a robust suite of capabilities for building modern distributed services.

Quick Start

Tarmac makes it easy to get started with building complex functions. The below function (written in Go) is an excellent example of its simplicity.

// Tac is a small, simple Go program that is an example WASM module for Tarmac. This program will accept a Tarmac
// server request, log it, and echo back the payload in reverse.
package main

import (
	"fmt"
	"github.com/tarmac-project/tarmac/pkg/sdk"
)

var tarmac *sdk.Tarmac

func main() {
	var err error

	// Initialize the Tarmac SDK
	tarmac, err = sdk.New(sdk.Config{Handler: Handler})
	if err != nil {
		return
	}
}

// Handler is the custom Tarmac Handler function that will receive a payload and
// must return a payload along with a nil error.
func Handler(payload []byte) ([]byte, error) {
	var err error

	// Log it
	tarmac.Logger.Trace(fmt.Sprintf("Reversing Payload: %s", payload))

	// Check Cache
	key := string(payload)
	rsp, err := tarmac.KV.Get(key)
	if err != nil || len(payload) < 1 {
		// Flip it and reverse
		if len(payload) > 0 {
			for i, n := 0, len(payload)-1; i < n; i, n = i+1, n-1 {
				payload[i], payload[n] = payload[n], payload[i]
			}
		}
		rsp = payload

		// Store in Cache
		err = tarmac.KV.Set(key, payload)
		if err != nil {
			tarmac.Logger.Error(fmt.Sprintf("Unable to cache reversed payload: %s", err))
			return rsp, nil
		}
	}

	// Return the payload
	return rsp, nil
}

To start running this function, navigate to our examples directory and run the make build command. The make build command compiles the code and generates a WebAssembly module.

$ cd example/tac/go
$ make build

Once compiled, you can run this function as a standalone microservice using the following Docker command.

$ docker run -p 8080:8080 \
  -e "APP_ENABLE_TLS=false" -e "APP_LISTEN_ADDR=0.0.0.0:8080" \
  -v `pwd`/functions:/functions madflojo/tarmac

With Tarmac now running, we can access our WASM function using any HTTP Client such as curl.

$ curl -v --data "Tarmac Example" http://localhost:8080

That's it! You can write and deploy functions in Go, Rust, AssemblyScript, Swift, or Zig with Tarmac. For more advanced functions, check out our developer guides.

Multi-Function Services

While users of Tarmac can build standalone microservices with a single function quickly, it shines with multi-function services. Tarmac's ability to run multiple functions means you can create purpose-built platforms with the developer experience of serverless functions.

To get started with multi-function services, you must provide a tarmac.json configuration file (via the WASM_FUNCTION_CONFIG configuration parameter) that lists the Functions to load and the various protocols and routes to expose as endpoints. Below is a sample tarmac.json configuration file.

{
  "services": {
    "my-service": {
      "name": "my-service",
      "functions": {
        "function1": {
          "filepath": "/path/to/function1.wasm"
        },
        "function2": {
          "filepath": "/path/to/function2.wasm"
        }
      },
      "routes": [
        {
          "type": "http",
          "path": "/function1",
          "methods": ["GET"],
          "function": "function1"
        },
        {
          "type": "http",
          "path": "/function2",
          "methods": ["POST"],
          "function": "function2"
        }
      ]
    }
  }
}

Each function has its own code base but shares the same service namespace and configurations in a multi-function service configuration.

In the example above, we have a service named my-service with function1 and function2 functions. Each function has a .wasm file at /path/to/function1.wasm and /path/to/function2.wasm.

To define the routes for each function, add a route object to the routes array with the type set to http and the function set to the function's name.

In addition to the http route type, Tarmac also supports scheduled_task routes that execute a function at a specific interval. The frequency parameter specifies the interval (in seconds).

{
  "type": "scheduled_task",
  "function": "function1",
  "frequency": 10
}

With Tarmac's support for multiple functions, you can quickly build complex, distributed services by dividing your service into smaller, more manageable pieces.

Architecture

Tarmac is a serverless platform that enables users to define and execute WebAssembly Functions. When Tarmac receives requests, it forwards them to WebAssembly Functions, which act as request handlers. The communication between Tarmac and WebAssembly Functions is via WebAssembly Procedure Calls (waPC).

By leveraging waPC, WebAssembly Functions can interact with Tarmac's core capabilities. Capabilities include performing callbacks to the Tarmac server to access key-value stores, interact with SQL databases, or make HTTP requests to downstream services.

To provide a streamlined developer experience, Tarmac offers a Go SDK that simplifies the usage of waPC. The SDK abstracts away the complexity of using waPC, allowing developers to focus on writing their functions and leveraging Tarmac's features.

Example Application Architecture

The below diagram shows the architecture of an example application. This application demonstrates how to build a multi-function service with Tarmac using Go.

This example application will execute WebAssembly functions on boot and via a scheduler to manage airport data. The application also includes an HTTP server that serves the airport data to clients via a WebAssembly function.

          +-------------------------------------------------------------------------------------------------------+                                 
          | Tarmac Host                                                                                           |                                 
          |                                       +------------------------------------------------------------+  |                                 
          |                                       | WebAssembly Engine                                         |  |                                 
          |                                       |                                                            |  |                                 
          |  +------------------------+           |  +-----------------------------------+                     |  |                                 
          |  |On Boot Function Trigger+-----------+-->Init: Creates DB Tables, Calls Load|                     |  |                                 
          |  +------------------------+           |  +--+--------------------------------+                     |  |                                 
          |                                       |     |                                                      |  |                                 
          |  +--------------------------+         |  +--v---------------------------------------------------+  |  |                                 
          |  |Scheduled Function Trigger+---------+--> Load: Calls Fetch, then loads results to SQL Database|  |  |                                 
          |  +--------------------------+         |  +--+---------------------------------------------------+  |  |                                 
          |                                       |     |                                                      |  |                                 
          |                                       |  +--v-----------------------------+                        |  |  +-----------------------------+
          |                                       |  | Fetch: Download AirportData.csv+------------------------+--+-->HTTP Server: AirportData.csv |
          |                                       |  +--------------------------------+                        |  |  +-----------------------------+
          |                                       |                                                            |  |                                 
+------+  |  +--------------------+               |  +----------------------------------+                      |  |                                 
|Client+--+-->HTTP Request Handler+---------------+-->Lookup: Fetches Data from Cache/DB|                      |  |                                 
+------+  |  +--------------------+               |  +----------------------------------+                      |  |                                 
          |                                       |                                                            |  |                                 
          |                                       +----------------------------+-------------------------------+  |                                 
          |                                                                    |                                  |                                 
          |                                                                    |                                  |                                 
          |                                                                    |                                  |                                 
          |                                       +----------------------------v-------------------------------+  |                                 
          |                                       | Tarmac Capabilities                                        |  |                                 
          |                                       |                                                            |  |                                 
          |                                       | +--------+ +------------+ +-------+ +------+               |  |                                 
          |                                       | |KV Store| |SQL Database| |Metrics| |Logger|               |  |                                 
          |                                       | +--------+ +------------+ +-------+ +------+               |  |                                 
          |                                       |                                                            |  |                                 
          |                                       +------------------------------------------------------------+  |                                 
          |                                                                                                       |                                 
          +-------------------------------------------------+-----------------------------------------------------+                                 
                                                            |                                                                                       
          +-------------------------------------------------v-----------------------------------------------------+                                 
          | External Services (Not all used in Example Application)                                               |                                 
          |                                                                                                       |                                 
          | +------+ +----------+ +-----+ +-----+ +----------+ +---------+                                        |                                 
          | |Consul| |Prometheus| |Redis| |MySQL| |PostgreSQL| |Cassandra|                                        |                                 
          | +------+ +----------+ +-----+ +-----+ +----------+ +---------+                                        |                                 
          |                                                                                                       |                                 
          +-------------------------------------------------------------------------------------------------------+                                 
Language
waPC Client
Tarmac SDK

AssemblyScript

✅

Go

✅

✅

Rust

✅

Swift

✅

Zig

✅

Contributing

We are thrilled that you are interested in contributing to Tarmac and helping to make it even better! To get started, please check out our contributing guide for information on how to submit bug reports, feature requests, and code contributions.

Project Contributors

SQL Datastore

Store and Retrieve data from a SQL datastore

The SQL Datastore capability provides WASM function developers the ability to store and retrieve data from SQL datastores. At the moment, Tarmac supports multiple SQL stores which can be enabled/disabled in the host configuration settings.

Query

The Query function provides users with the ability to execute custom SQL queries against the database service. The returned data is in JSON format and base64 encoded to avoid format conflicts.

Interface Details

Namespace
Capability
Function
Input
Output

Example JSON

This callback uses JSON messages as input and output to facilitate communications between WASM functions and the Tarmac host.

SQLQuery

To avoid format and data conflicts the query itself must be base64 encoded.

SQLQueryResponse

To avoid format and data conflicts the data returned is base64 encoded.

The Status structure within the response JSON denotes the success of the database call. The status code value follows the HTTP status code standards, with anything higher than 399 is an error.

Metrics

Custom Metrics for WASM Functions

The Metrics capability provides WASM function developers the ability to create user-defined metrics exposed as part of the Tarmac /metrics end-point. This capability supports the three predominant metrics types, Counters, Gauges, & Histograms.

Counter

The Counter function will give users the ability to create a custom counter metric. When called, this function will increment the counter by one.

Interface Details

Namespace
Capability
Function
Input
Output

Example JSON

This callback uses JSON messages as input and output to facilitate communications between WASM functions and the Tarmac host.

MetricsCounter

Gauge

The Gauge function will give users the ability to create a custom gauge metric. When called, this function will either increment or decrement the gauge by one.

Interface Details

Namespace
Capability
Function
Input
Output

Example JSON

This callback uses JSON messages as input and output to facilitate communications between WASM functions and the Tarmac host.

MetricsCounter

Valid actions are inc (Increment) and dec (Decrement).

Histogram

The Histogram function will give users the ability to create a custom histogram metric. When called, this function will observe the provided value and summarize the metric results.

Interface Details

Namespace
Capability
Function
Input
Output

Example JSON

This callback uses JSON messages as input and output to facilitate communications between WASM functions and the Tarmac host.

MetricsCounter

Go

Creating a WASM Function in Go.

Tarmac leverages the Web Assembly System Interface (WASI), which is currently only supported by . While TinyGo has many features, there are some limitations to its support.

However, thanks to the Go SDK, writing Tarmac functions is quick and easy. This guide will walk users through creating a simple function using Go.

Basic WASM function

We will first need to begin with a new project folder creating a main.go file within it. This file will hold all of our application logic.

Within our main.go file; we will need first to import the Tarmac Go SDK.

Once we've imported the SDK, we will need to both create our Function and register it with the SDK. We will start by initializing the SDK and registering our Function, Handler().

As Tarmac receives requests such as an HTTP POST request, the Handler() function will be called with the HTTP payload provided as the payload parameter.

We can create our Function, which returns a simple "Howdie" message.

Building the WASM Function

Now that our function is ready, we must compile our Go code into a .wasm file. To do this, we will be using TinyGo.

The first step above is using mkdir to create a functions directory, this is not required but will be helpful when running Tarmac in the next stage.

After the functions directory is created, we are using the tinygo command to build our .wasm file. The inclusion of -target wasi is important as it directs TinyGo to compile the Go code using the Web Assembly System Interface (wasi) standard. This standard is useful for running Web Assembly on the server vs. on the browser.

With this step complete, we have built our WASM function.

Running the WASM Function

We are now ready to run our WASM function via Tarmac. To make this process easier, we will be using Docker to execute Tarmac. It is not necessary to use Docker with Tarmac as it can run outside of Docker as well.

In the above command, we are passing two environment variables to the container using the -e flag. These environment variables will tell Tarmac to use HTTP rather than HTTPS, which is the default. For additional configuration options, check out the documentation.

With Tarmac now running, we can access our WASM function using any HTTP Client such as curl.

Expanding beyond Hello World

While the above Hello World example provides an excellent introduction to creating Go functions, it does not showcase the power of Tarmac.

Tarmac provides integrations with many of the capabilities required to build today's modern platforms. These capabilities include Key:Value datastores such as Redis or Cassandra. The ability to create metrics for observability and log messages via a structured logger. Or even the ability to call HTTP end-points with an HTTP Client.

These integrations are simple to call with the Go SDK; the below Function showcases several capabilities, such as calling a key:value cache and logging.

Conclusion

Developers can use this guide to get started with WASM functions and using Tarmac. Some of the information in this guide is subject to change as support for WASM in Go advances.

_, err := wapc.HostCall("tarmac", "sql", "query", `SQLQueryJSON`)

tarmac

sql

query

SQLQuery

SQLQueryResponse

{
	"query": "c2VsZWN0ICogZnJvbSBleGFtcGxlOw=="
}
{
	"data": "W3siaWQiOjEsIm5hbWUiOiJKb2huIFNtaXRoIn0seyJpZCI6MSwibmFtZSI6IkphbmUgU21pdGgifV0=",
	"status": {
		"code": 200,
		"status": "OK"
	}
}
_, err := wapc.HostCall("tarmac", "metrics", "counter", MetricsCounterJSON)

tarmac

metrics

counter

MetricsCounter

nil

{
	"name": "custom_metric_name"
}
_, err := wapc.HostCall("tarmac", "metrics", "gauge", MetricsGaugeJSON)

tarmac

metrics

gauge

MetricsGauge

nil

{
	"name": "custom_metric_name",
	"action": "inc"
}
_, err := wapc.HostCall("tarmac", "metrics", "histogram", MetricsHistogramJSON)

tarmac

metrics

histogram

MetricsHistogram

nil

{
	"name": "custom_metric_name",
	"value": 0.0001
}
package main

import (
	"github.com/tarmac-project/tarmac/pkg/sdk"
)
func main() {
	// Initialize the Tarmac SDK
	_, err := sdk.New(sdk.Config{Namespace: "test-service", Handler: Handler})
	if err != nil {
		return
	}
}
func Handler(payload []byte) ([]byte, error) {
	// Return a happy message
	return []byte("Howdie"), nil
}
$ mkdir -p functions
$ tinygo build -o functions/tarmac.wasm -target wasi main.go
$ docker run -p 8080:8080 \
  -e "APP_ENABLE_TLS=false" -e "APP_LISTEN_ADDR=0.0.0.0:8080" \
  -v `pwd`./functions:/functions madflojo/tarmac
$ curl -v --data "Tarmac Example" http://localhost:8080
// Tac is a small, simple Go program that is an example WASM module for Tarmac. This program will accept a Tarmac
// server request, log it, and echo back the payload in reverse.
package main

import (
	"fmt"
	"github.com/tarmac-project/tarmac/pkg/sdk"
)

var tarmac *sdk.Tarmac

func main() {
	var err error

	// Initialize the Tarmac SDK
	tarmac, err = sdk.New(sdk.Config{Handler: Handler})
	if err != nil {
		return
	}
}

// Handler is the custom Tarmac Handler function that will receive a payload and
// must return a payload along with a nil error.
func Handler(payload []byte) ([]byte, error) {
	var err error

	// Log it
	tarmac.Logger.Trace(fmt.Sprintf("Reversing Payload: %s", payload))

	// Check Cache
	key := string(payload)
	rsp, err := tarmac.KV.Get(key)
	if err != nil || len(payload) < 1 {
		// Flip it and reverse
		if len(payload) > 0 {
			for i, n := 0, len(payload)-1; i < n; i, n = i+1, n-1 {
				payload[i], payload[n] = payload[n], payload[i]
			}
		}
		rsp = payload

		// Store in Cache
		err = tarmac.KV.Set(key, payload)
		if err != nil {
			tarmac.Logger.Error(fmt.Sprintf("Unable to cache reversed payload: %s", err))
			return rsp, nil
		}
	}

	// Return the payload
	return rsp, nil
}
TinyGo
Configuration

Logger

Standard logging capabilities

The Logger capability provides WASM functions with the ability to log arbitrary data. Much like a traditional logger framework, this capability offers multiple log levels.

By default Debug and Trace level logs are disabled. To enable these log levels to consult the configuration options for Tarmac.

Error

Critical errors within the system.

_, err := wapc.HostCall("tarmac", "logger", "error", []byte("This is the data that should be logged"))

Interface Details

Namespace
Capability
Function
Input
Output

tarmac

logger

error

Log Message

nil

Warn

Non-critical errors within the system.

_, err := wapc.HostCall("tarmac", "logger", "warn", []byte("This is the data that should be logged"))

Interface Details

Namespace
Capability
Function
Input
Output

tarmac

logger

warn

Log Message

nil

Info

Informational logs.

_, err := wapc.HostCall("tarmac", "logger", "info", []byte("This is the data that should be logged"))

Interface Details

Namespace
Capability
Function
Input
Output

tarmac

logger

info

Log Message

nil

Debug

Request level errors & informational logs. Disabled by default, calls to Debug logging are ignored unless debug is enabled for the Tarmac host.

_, err := wapc.HostCall("tarmac", "logger", "debug", []byte("This is the data that should be logged"))

Interface Details

Namespace
Capability
Function
Input
Output

tarmac

logger

debug

Log Message

nil

Trace

Low-level details of execution. Disabled by default, calls to Trace logging are ignored unless trace is enabled for the Tarmac host.

_, err := wapc.HostCall("tarmac", "logger", "trace", []byte("This is the data that should be logged"))

Interface Details

Namespace
Capability
Function
Input
Output

tarmac

logger

trace

Log Message

nil

Key:Value Datastore

Store and Retrieve data from a Key:Value datastore

The Key:Value Store capability provides WASM function developers the ability to store and retrieve data from Key:Value datastores. At the moment, Tarmac supports multiple Key:Value stores which can be enabled/disabled in the host configuration settings.

Get

The Get function provides users with the ability to fetch data using the specified key. To avoid conflicts, the data key within the response, JSON, will be base64 encoded.

_, err := wapc.HostCall("tarmac", "kvstore", "get", KVStoreGetJSON)

Interface Details

Namespace
Capability
Function
Input
Output

tarmac

kvstore

get

KVStoreGet

KVStoreGetResponse

Example JSON

This callback uses JSON messages as input and output to facilitate communications between WASM functions and the Tarmac host.

KVStoreGet

{
	"key": "myKey"
}

KVStoreGetResponse

{
	"data": "VHdlZXQgYWJvdXQgVGFybWFjIGlmIHlvdSB0aGluayBpdCdzIGF3ZXNvbWUu",
	"status": {
		"code": 200,
		"status": "OK"
	}
}

The Status structure within the response JSON denotes the success of the database call. The status code value follows the HTTP status code standards, with anything higher than 399 is an error.

Set

The Set function provides users with the ability to store data within the Key:Value datastore. The data key within the request JSON must be base64 encoded.

_, err := wapc.HostCall("tarmac", "kvstore", "set", KVStoreSetJSON)

Interface Details

Namespace
Capability
Function
Input
Output

tarmac

kvstore

set

KVStoreSet

KVStoreSetResponse

Example JSON

This callback uses JSON messages as input and output to facilitate communications between WASM functions and the Tarmac host.

KVStoreSet

{
  "data": "VHdlZXQgYWJvdXQgVGFybWFjIGlmIHlvdSB0aGluayBpdCdzIGF3ZXNvbWUu",
  "key": "myKey"
}

KVStoreSetResponse

{
  "status": {
    "code": 200,
    "status": "OK"
  }
}

The Status structure within the response JSON denotes the success of the database call. The status code value follows the HTTP status code standards, with anything higher than 399 is an error.

Delete

The Delete function provides users with the ability to delete data stored within the Key:Value datastore.

_, err := wapc.HostCall("tarmac", "kvstore", "delete", KVStoreDeleteJSON)

Interface Details

Namespace
Capability
Function
Input
Output

tarmac

kvstore

delete

KVStoreDelete

KVStoreDeleteResponse

Example JSON

This callback uses JSON messages as input and output to facilitate communications between WASM functions and the Tarmac host.

KVStoreDelete

{
  "key": "myKey"
}

KVStoreDeleteResponse

{
  "status": {
    "code": 200,
    "status": "OK"
  }
}

The Status structure within the response JSON denotes the success of the database call. The status code value follows the HTTP status code standards, with anything higher than 399 is an error.

Keys

The Keys function provides users with the ability to fetch a list of all keys available within the Key:Value datastore.

_, err := wapc.HostCall("tarmac", "kvstore", "keys", []byte())

Note: This callback requires no input JSON. However, the callback function will require users to provide a byte slice.

Interface Details

Namespace
Capability
Function
Input
Output

tarmac

kvstore

keys

EmptyByteSlice

KVStoreKeysResponse

Example JSON

This callback uses JSON messages as input and output to facilitate communications between WASM functions and the Tarmac host.

KVStoreKeysResponse

{
	"keys": ["key1", "key2"],
	"status": {
		"code": 200,
		"status": "OK"
	}
}

The Status structure within the response JSON denotes the success of the database call. The status code value follows the HTTP status code standards, with anything higher than 399 is an error.

HTTP Client

Make HTTP requests with a simple HTTP client

The HTTPClient capability provides WASM function developers to perform HTTP client requests to remote or local HTTP servers. While a simplistic client, Tarmac supports multiple HTTP requests, setting headers, and custom payloads.

Call

The Call function provides users with the ability to make HTTP client requests to the specified URL. The body key within the request and response JSON will be base64 encoded to avoid conflicts.

_, err := wapc.HostCall("tarmac", "httpclient", "call", HTTPClientJSON)

Interface Details

Namespace
Capability
Function
Input
Output

tarmac

httpclient

call

HTTPClient

HTTPClientResponse

Example JSON

This callback uses JSON messages as input and output to facilitate communications between WASM functions and the Tarmac host.

HTTPClient

{
	"method": "POST",
	"headers": {
		"content-type": "application/json"
	},
	"insecure": true,
	"url": "http://example.com",
	"body": "ewoJIm1lIjogewoJCSJ0ZWFwb3QiOiB0cnVlCgl9Cn0="
}

HTTPClientResponse

{
	"code": 400,
	"headers": {
		"key": "value"
	},
	"body": "dGlwIG1lIG92ZXIgYW5kIHBvdXIgbWUgb3V0",
	"status": {
		"code": 200,
		"status": "OK"
	}
}

The Status structure within the response JSON denotes the success of the database call. The status code value follows the HTTP status code standards, with anything higher than 399 is an error.

Note: Tarmac will provide a 200 status code if the HTTP request was successfully made, check the code value to validate the HTTP server return code.

Datastores

Configuration

Configuring Tarmac

Tarmac supports multiple configuration sources such as Environment Variables, JSON files, or using HashiCorp Consul. All of these configuration options can also exist together to provide both static and dynamic configurations.

When using Environment Variables, all configurations are prefixed with APP_. The list below will show both Environment and Consul/JSON format for configuration.

Environment Variable
Consul/JSON
Type
Description

APP_ENABLE_TLS

enable_tls

bool

Enable the HTTPS Listener (default: True)

APP_LISTEN_ADDR

listen_addr

string

Define the HTTP/HTTPS Listener address (default: 0.0.0.0:8443)

APP_CONFIG_WATCH_INTERVAL

config_watch_interval

int

Frequency in seconds which Consul configuration will be refreshed (default: 15)

APP_USE_CONSUL

use_consul

bool

Enable Consul based configuration (default: False)

APP_CONSUL_ADDR

consul_addr

string

Consul address (i.e. consul.example.com:8500)

APP_CONSUL_KEYS_PREFIX

consul_keys_prefix

string

Key path for app specific consul configuration

from_consul

bool

Indicator to reflect whether Consul config was loaded

APP_DEBUG

debug

bool

Enable debug logging

APP_TRACE

trace

bool

Enable trace logging

APP_DISABLE_LOGGING

disable_logging

bool

Disable all logging

APP_TEXT_LOG_FORMAT

text_log_format

bool

Use text format for logs instead of JSON (default: False)

APP_CERT_FILE

cert_file

string

Certificate File Path (i.e. /some/path/cert.crt)

APP_KEY_FILE

key_file

string

Key File Path (i.e. /some/path/cert.key)

APP_CA_FILE

ca_file

string

Certificate Authority Bundle File Path (i.e /some/path/ca.pem). When defined, enables mutual-TLS authentication

APP_IGNORE_CLIENT_CERT

ignore_client_cert

string

When defined will disable Client Cert validation for m-TLS authentication

APP_WASM_FUNCTION

wasm_function

string

Path and Filename of the WASM Function to execute (Default: /functions/tarmac.wasm)

APP_WASM_FUNCTION_CONFIG

wasm_function_config

string

Path to Service configuration for multi-function services (Default: /functions/tarmac.json)

APP_WASM_POOL_SIZE

wasm_pool_size

int

Number of WASM function instances to create (Default: 100). Only applicable when wasm_function is used.

APP_ENABLE_PPROF

enable_pprof

bool

Enable PProf Collection HTTP end-points

APP_ENABLE_KVSTORE

enable_kvstore

bool

Enable the KV Store

APP_KVSTORE_TYPE

kvstore_type

string

Select KV Store to use (Options: redis, cassandra, boltdb, in-memory, internal)

APP_ENABLE_SQL

enable_sql

bool

Enable the SQL Store

APP_SQL_TYPE

sql_type

string

Select SQL Store to use (Options: postgres, mysql)

APP_RUN_MODE

run_mode

string

Select the run mode for Tarmac (Options: daemon, job). Default: daemon. The job option will cause Tarmac to exit after init functions are executed.

APP_ENABLE_MAINTENANCE_MODE

enable_maintenance_mode

bool

Enable Maintenance Mode. When enabled, Tarmac will return a 503 for requests to /ready allowing the service to go into "maintenance mode".

Consul Format

When using Consul the consul_keys_prefix should be the path to a key with a JSON string as the value. For example, a key of tarmac/config will have a value of {"from_consul":true}.

Functions

Function to Function calls

The Functions capability allows WASM functions to call other WASM functions. Unlike other callback capabilities, functions must register within the routes configuration within the tarmac.json configuration file.

Function

Interface Details

Namespace
Capability
Function
Input
Output

Cassandra

Configuring Tarmac with Cassandra

This page contains Cassandra specific configuration to utilize Cassandra with Tarmac.

Tarmac supports multiple configuration sources such as Environment Variables, JSON files, or using HashiCorp Consul. All of these configuration options can also exist together to provide both static and dynamic configurations.

When using Environment Variables, all configurations are prefixed with APP_. The list below will show both Environment and Consul/JSON format for configuration.

Environment Variable
Consul/JSON
Type
Description

Consul Format

When using Consul the consul_keys_prefix should be the path to a key with a JSON string as the value. For example, a key of tarmac/config will have a value of {"from_consul":true}.

Key:Value

Selecting a KV Store

Tarmac has support for multiple Key:Value datastore storage systems. These datastores can change with basic configuration options within Tarmac. As a WASM Function developer, you do not need to know the underlying datastore when writing the function. Callbacks for accessing the Key:Value datastore are generic across all supported datastores.

To start using a Key:Value datastore, set the enable_kvstore configuration to true and specify which supported platform to use with the kvstore_type variable.

The below table outlines the different available options.

Datastore
Type option
Description
Useful for

For more detailed configuration options, check out the documentation.

BoltDB

Configuring Tarmac with BoltDB

This page contains BoltDB specific configuration to utilize BoltDB with Tarmac.

Tarmac supports multiple configuration sources such as Environment Variables, JSON files, or using HashiCorp Consul. All of these configuration options can also exist together to provide both static and dynamic configurations.

When using Environment Variables, all configurations are prefixed with APP_. The list below will show both Environment and Consul/JSON format for configuration.

Environment Variable
Consul/JSON
Type
Description

Consul Format

When using Consul the consul_keys_prefix should be the path to a key with a JSON string as the value. For example, a key of tarmac/config will have a value of {"from_consul":true}.

_, err := wapc.HostCall("tarmac", "function", "function-name", []byte("Input to Function"))

tarmac

function

Function Name

Input Data

Function Output Data

In-Memory

in-memory

In-Memory key/value store

Testing, Development, Non-Persistent Caching

BoltDB

boltdb

BoltDB Embedded key/value store

Strong Consistency, Persistent Storage

Redis

redis

Redis including Sentinel and Enterprise capabilities

Strong Consistency, Fast Reads and Writes, Non-Persistent storage

Cassandra

cassandra

Cassandra including TLS connectivity

Eventual Consistency, Persistent Storage, Large sets of data

Configuration

APP_CASSANDRA_HOSTS

cassandra_hosts

[]string

Cassandra node addresses

APP_CASSANDRA_PORT

cassandra_port

int

Cassandra node port

APP_CASSANDRA_KEYSPACE

cassandra_keyspace

string

Cassandra Keyspace name

APP_CASSANDRA_CONSISTENCY

cassandra_consistency

string

Desired Consistency (Default: Quorum)

APP_CASSANDRA_REPL_STRATEGY

cassandra_repl_strategy

string

Replication Strategy for Cluster (Default: SimpleStrategy)

APP_CASSANDRA_REPLICAS

cassandra_replicas

int

Default number of replicas for data (Default: 1)

APP_CASSANDRA_USER

cassandra_user

string

Username to authenticate with

APP_CASSANDRA_PASSWORD

cassandra_password

string

Password to authenticate with

APP_CASSANDRA_HOSTNAME_VERIFY

cassandra_hostname_verify

bool

Enable/Disable hostname verification for TLS

APP_BOLTDB_FILENAME

boltdb_filename

string

The full path and filename of the BoltDB file. If the file does not exist, it will be created.

APP_BOLTDB_BUCKET

boltdb_bucket

string

The name of the BoltDB bucket to use. If the bucket does not exist, it will be created.

APP_BOLTDB_PERMISSIONS

boltdb_permissions

int

The permissions to use when creating the BoltDB file. This is an octal value.

APP_BOLTDB_TIMEOUT

boltdb_timeout

int

The timeout in seconds to wait for BoltDB to open.

Monitoring

Monitoring Tarmac with Prometheus Metrics

Tarmac exposes several metrics to facilitate monitoring services. Metrics are available via the /metrics end-point in the Prometheus format.

These metrics include internal Tarmac system metrics such as the number of goroutines, memory utilization, and WASM function-specific metrics such as counters for Callbacks and WASM function execution time.

Some valuable metrics to monitor are in the below table.

Metric Name
Metric Type
Description

http_server

Summary

Summary of HTTP Server requests

scheduled_tasks

Summary

Summary of user defined scheduled task WASM function executions

wasm_callbacks

Summary

Summary of Tarmac callback function executions

wasm_functions

Summary

Summary of wasm function executions

These metrics do not need to be enabled and are "on by default".

Logging

Logging options of Tarmac

Tarmac uses structured logging to provide detailed information about system operations. By default, logs are output in JSON format, which is ideal for automated log processing and analysis tools.

Log Format

Administrators can control the format of Tarmac's logs:

  • JSON Format (Default): Structured logging that's machine-readable and easily parsed by log aggregation tools

  • Text Format: Human-readable plain text format that's easier to read in the console or log files

To use text format instead of JSON, set the text_log_format configuration option to true.

Controlling Log Levels

Administrators can control Tarmac's logging levels dynamically while using a distributed configuration service such as Consul. As a WASM Function developer, you can select which logging level you wish your log callbacks to use.

As an Administrator, you can choose to enable or disable dynamically certain log levels such as Debug or Trace. To do this, modify the debug and trace configuration options within Consul.

It is also possible to disable all logging by changing the disable_logging configuration option to true.

For more information on connecting Tarmac with Consul, consult our Configuration documentation.

SQL

Selecting a SQL Datastore

Tarmac has support for multiple SQL datastore storage systems. These datastores can change with basic configuration options within Tarmac. As a WASM Function developer, you do not need to know the underlying datastore when writing the function. Callbacks for accessing the SQL datastore are generic across all supported datastores.

To start using a SQL datastore, set the enable_sql configuration to true and specify which supported platform to use with the sqlstore_type variable.

The below table outlines the different available options.

Datastore
Type option
Description
Useful for

MySQL

mysql

MySQL a widely used, open-source RDBMS

Strong Consistency, Well Known, Persistent Storage, Scales Well

PostgreSQL

postgres

PostgreSQL a widely used, open-source RDBMS

Strong Consistency, Well Known, Persistent Storage, Scales Well

For more detailed configuration options, check out the Configuration documentation.

Redis

Configuring Tarmac with Redis

This page contains Redis specific configuration to utilize Redis with Tarmac.

Tarmac supports multiple configuration sources such as Environment Variables, JSON files, or using HashiCorp Consul. All of these configuration options can also exist together to provide both static and dynamic configurations.

When using Environment Variables, all configurations are prefixed with APP_. The list below will show both Environment and Consul/JSON format for configuration.

Environment Variable
Consul/JSON
Type
Description

APP_REDIS_SERVER

redis_server

string

Redis server address

APP_REDIS_DATABASE

redis_database

int

Redis Database (default: 0)

APP_REDIS_PASSWORD

redis_password

string

Redis password

APP_REDIS_SENTINEL_SERVERS

redis_sentinel_servers

[]string

Redis Sentinel Server Addresses

APP_REDIS_SENTINEL_MASTER

redis_sentinel_master

string

Redis Sentinel Master Instance Name

APP_REDIS_CONNECT_TIMEOUT

redis_connect_timeout

int

Redis Connection Timeout in seconds

APP_REDIS_HOSTNAME_VERIFY

redis_hostname_verify

bool

Skip hostname verification for TLS

APP_REDIS_KEEPALIVE

redis_keepalive

int

TCP Keepalive Interval in seconds (Default: 300)

APP_REDIS_MAX_ACTIVE

redis_max_active

int

Max Active Connections

APP_REDIS_READ_TIMEOUT

redis_read_timeout

int

Read timeout in seconds

APP_REDIS_WRITE_TIMEOUT

redis_write_timeout

int

Write timeout in seconds

Consul Format

When using Consul the consul_keys_prefix should be the path to a key with a JSON string as the value. For example, a key of tarmac/config will have a value of {"from_consul":true}.

Troubleshooting Performance

Profiling a running Tarmac instance

Troubleshooting Performance Issues or Memory leaks within running services can be a complex task. Luckily, Tarmac uses the native Go tooling to create profiling snapshots of a running instance.

PProf is a Go tool for capturing and visualizing profiling data. Tarmac uses the net/http/pprof package to make PProf available via HTTP end-points.

By default, all PProf end-points are disabled, preventing unauthorized use of PProf (which itself can affect performance). To enable PProf, set the Configuration value of enable_pprof to true. Using a distributed configuration service such as Consul, users can change this value live without restarting the application instance.

Follow the for more details on configuring Tarmac.

Once enabled, users can use the following end-points to capture profiling data.

URI
Description

More information about PProf can be found via the .

/debug/pprof

PProf Index linking to individual profiling pages

/debug/pprof/allocs

A sampling of all past memory allocations

/debug/pprof/block

Stack traces that led to blocking on synchronization primitives

/debug/pprof/cmdline

The command line invocation of the current program

/debug/pprof/goroutine

Stack traces of all current goroutines

/debug/pprof/heap

A sampling of memory allocations of live objects

/debug/pprof/mutex

Stack traces of holders of contended mutexes

/debug/pprof/profile

CPU Profile

/debug/pprof/threadcreate

Stack traces that led to the creation of new OS threads

/debug/pprof/trace

A trace of execution of the current program

Configuration guide
official documentation