Developing UDF Modules
For the complete documentation index see: llms.txt
All documentation pages available in markdown.
Modules Written in Lua
A Lua module is a collection of variables and functions contained in a single file. Modules can be imported and used by other Lua modules, including UDFs. A module name must not conflict with other Lua objects pre-registered by the Aerospike server. The following module names should be avoided:
- aerospike
- bytes
- geojson
- iterator
- list
- map
- record
- stream
Module filename rules
Available in Aerospike Database 8.1.2.2, 8.0.0.17, 7.2.0.19, 7.1.0.25 and later. UDF module names must conform to a fixed allowlist. See UDF security and sandbox hardening for the rules and migration guidance for entries that fail validation after upgrade.
Sandbox modes
Aerospike runs every UDF in an embedded Lua state. The set of Lua libraries available to UDFs depends on the mod-lua.allow-unsafe-lua configuration option.
Default mode (allow-unsafe-lua=true): The following restrictions apply.
- The Lua
iolibrary is not available. - The Lua
oslibrary is restricted toos.clock(),os.date(),os.difftime(), andos.time(). - The Lua
debuglibrary is not available. os.exit()is not available.
Hardened mode (allow-unsafe-lua=false): Hardened mode replaces the default sandbox with stricter restrictions:
- The
os,io,debug,dofile,loadfile,load, andloadstringglobals are removed entirely. The fouros.*functions allowed in default mode are not available in hardened mode. package.searchpath,package.loadlib, andpackage.cpathare removed.- Native
.soUDF modules cannot be registered. See Using C functions in UDF Modules later on this page. - Precompiled Lua bytecode UDFs are rejected at registration with a compile error; the server loads Lua chunks in text-only mode.
- The
.luaextension is checked case-sensitively at registration.
See UDF security and sandbox hardening for the full set of changes and a migration checklist.
Creating a Module
In the following example, we define a local table exports in the file mymodule.lua. This module will be
populated with the functions to be exported.
local exports = {}
function exports.hello() return "Hello "end
function exports.world() return "World!"end
return exportsRegistering a Module
Lua Modules must be registered with the Aerospike Server.
To install your modules, you may
To register the module using asadm:
Admin> enableAdmin+> manage udfs add mymodule.lua path path/to/mymodule.luaSuccessfully added UDF mymodule.luaAdmin+>Admin+> show udfs~~~~~~~~~~UDF Modules (2021-01-23 02:00:18 UTC)~~~~~~~~~~~ Filename| Hash|Typemymodule.lua|7fae110826972135a3c3b8a812d43243e7c7a23c|LUANumber of rows: 1To register the module using aql:
aql> register module 'mymodule.lua'OK, 1 module added.
aql> show modules+-----------------+--------------------------------------------+-------+| filename | hash | type |+-----------------+--------------------------------------------+-------+| "mymodule.lua" | "4e4dfd2ac120e161f69d1dfbab14eec157d0eaaf" | "LUA" |+-----------------+--------------------------------------------+-------+Another module can now require mymodule.lua into a local variable and use
it.
Example: A Hello World UDF
In a file example.lua
local mm = require('mymodule')
function helloworld(rec) return mm.hello() .. mm.world()endIn aql
aql> register module 'example.lua'OK, 1 module added.
aql> show modules+-----------------+--------------------------------------------+-------+| filename | hash | type |+-----------------+--------------------------------------------+-------+| "example.lua" | "c42bf3f4a6f8f727efcfb884c97ee894764f1dc7" | "LUA" || "mymodule.lua" | "4e4dfd2ac120e161f69d1dfbab14eec157d0eaaf" | "LUA" |+-----------------+--------------------------------------------+-------+2 rows in set (0.002 secs)
aql> insert into test.foo (PK, x) values ('1', 24)OK, 1 record affected.
aql> execute example.helloworld() on test.foo where PK='1'+----------------+| helloworld |+----------------+| "Hello World!" |+----------------+1 row in set (0.001 secs)Using C functions in UDF Modules
Aerospike UDFs written in Lua can call C functions from shared objects. For more information read about the C API for Lua.
Example: Compiling and Registering a Shared Object
In this example the file power.c contains sample C code:
#include <lua.h>#include <lauxlib.h>#include <lualib.h>
static int go(lua_State * L) { int rtrn = lua_tonumber(L, -1); /* Get the single number arg */ lua_pushnumber(L,rtrn*rtrn); /* square it and push the return */
return 1;}
static const struct luaL_reg golib [] = { {"go", go}, {NULL, NULL}};
int luaopen_power(lua_State * L) { luaL_openlib(L, "go", golib, 0); return 1;}The Lua UDF module use.lua requires and calls the power.so shared object
function thepower(rec, basenum) local power = require("power") local rtn = power.go(basenum); --info(rtn) return rtnendGet the Lua Source
Download the Lua 5.1.4 library to allow for the necessary Lua code to be linked.
Compile
gcc -fPIC -o power.so -shared power.c -I /usr/include/Register and Execute
In aql:
aql> register module 'power.so'OK, 1 module added.
aql> register module 'use.lua'OK, 1 module added.
aql> show modules+-----------------+--------------------------------------------+-------+| filename | hash | type |+-----------------+--------------------------------------------+-------+| "example.lua" | "c42bf3f4a6f8f727efcfb884c97ee894764f1dc7" | "LUA" || "power.so" | "99703e01482f065c62f0d0c55ba6b1f3214e3601" | "LUA" || "use.lua" | "5093704498b333e57d7dd033b529c4b4e0d99edb" | "LUA" || "mymodule.lua" | "4e4dfd2ac120e161f69d1dfbab14eec157d0eaaf" | "LUA" |+-----------------+--------------------------------------------+-------+4 rows in set (0.002 secs)
aql> execute use.thepower(4) on test.foo where PK='1'+----------+| thepower |+----------+| 16 |+----------+1 row in set (0.001 secs)