From: Marek VavruĊĦa Date: Wed, 6 May 2015 08:28:21 +0000 (+0200) Subject: daemon/engine: support for Lua modules, stub etcd module X-Git-Tag: v1.0.0-beta1~211 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=073fb627b909226c932101524bc3194bf01fc27c;p=thirdparty%2Fknot-resolver.git daemon/engine: support for Lua modules, stub etcd module --- diff --git a/daemon/engine.c b/daemon/engine.c index a5eb274ee..8507b0849 100644 --- a/daemon/engine.c +++ b/daemon/engine.c @@ -95,6 +95,59 @@ static int l_trampoline(lua_State *L) return 0; } +/** @internal Helper for retrieving the right function entrypoint. */ +static inline lua_State *l_ffi_preface(struct kr_module *module, const char *call) { + lua_State *L = module->lib; + lua_rawgeti(L, LUA_REGISTRYINDEX, (intptr_t)module->data); + lua_getfield(L, -1, call); + lua_pushlightuserdata(L, module); + return L; +} + +/** @internal Helper for calling the entrypoint. */ +static inline int l_ffi_call(lua_State *L) { + if (engine_pcall(L, 1) != 0) { + lua_pop(L, 1); + return kr_error(EIO); + } + return lua_tonumber(L, 1); +} + +static int l_ffi_init(struct kr_module *module) +{ + lua_State *L = l_ffi_preface(module, "init"); + return l_ffi_call(L); +} + +static int l_ffi_config(struct kr_module *module, const char *conf) +{ + lua_State *L = l_ffi_preface(module, "config"); + lua_pushstring(L, conf); + return l_ffi_call(L); +} + +static int l_ffi_deinit(struct kr_module *module) +{ + lua_State *L = l_ffi_preface(module, "deinit"); + int ret = l_ffi_call(L); + /* Unref module and unset 'lib', so the module + * interface doesn't attempt to close it. + */ + luaL_unref(L, LUA_REGISTRYINDEX, (intptr_t)module->data); + module->lib = NULL; + return ret; +} + +static const knot_layer_api_t* l_ffi_layer(struct kr_module *module) +{ + /* lua_State *L = l_ffi_preface(module, "layer"); */ + /** @todo Pickle access to context somewhere */ + /** @todo Store the returned table in the registry */ + /** @todo Keep the reference in the api_t */ + /** @todo Make trampoline functions for layer operations. */ + return NULL; +} + /* * Engine API. */ @@ -284,6 +337,41 @@ void engine_stop(struct engine *engine) uv_stop(uv_default_loop()); } +/** @internal Helper macro for function presence check. */ +#define REGISTER_FFI_CALL(L, attr, name, cb) do { \ + lua_getfield((L), -1, (name)); \ + if (!lua_isnil((L), -1)) { attr = cb; } \ + lua_pop((L), 1); \ + } while (0) + +/** Register Lua module as a FFI module */ +static int register_lua_module(struct engine *engine, struct kr_module *module, const char *name) +{ + /* Register module in Lua */ + lua_State *L = engine->L; + lua_getglobal(L, "require"); + lua_pushstring(L, name); + if (engine_pcall(L, 1) != 0) { + lua_pop(L, 1); + return kr_error(ENOENT); + } + lua_setglobal(L, name); + lua_getglobal(L, name); + + /* Create FFI module with trampolined functions. */ + memset(module, 0, sizeof(*module)); + module->name = strdup(name); + REGISTER_FFI_CALL(L, module->init, "init", &l_ffi_init); + REGISTER_FFI_CALL(L, module->deinit, "deinit", &l_ffi_deinit); + REGISTER_FFI_CALL(L, module->config, "config", &l_ffi_config); + REGISTER_FFI_CALL(L, module->layer, "layer", &l_ffi_layer); + module->lib = L; + module->data = (void *)(intptr_t)luaL_ref(L, LUA_REGISTRYINDEX); + return module->init(module); +} + +#undef REGISTER_FFI_CALL + /** Register module properties in Lua environment */ static int register_properties(struct engine *engine, struct kr_module *module) { @@ -316,12 +404,15 @@ int engine_register(struct engine *engine, const char *name) /* Make sure module is unloaded */ (void) engine_unregister(engine, name); - - /* Load module */ + /* Attempt to load binary module */ size_t next = engine->modules.len; array_reserve(engine->modules, next + 1); struct kr_module *module = &engine->modules.at[next]; int ret = kr_module_load(module, name, NULL); + /* Load Lua module if not a binary */ + if (ret == kr_error(ENOENT)) { + ret = register_lua_module(engine, module, name); + } if (ret != 0) { return ret; } else { diff --git a/modules/ketcd/README.rst b/modules/ketcd/README.rst new file mode 100644 index 000000000..7a48127bf --- /dev/null +++ b/modules/ketcd/README.rst @@ -0,0 +1,14 @@ +.. _mod-etcd: + +Etcd module +----------- + +.. warning:: Work in progress! + +Dependencies +^^^^^^^^^^^^ + +* `lua-etcd `_ available in LuaRocks + + $ luarocks install etcd --from=http://mah0x211.github.io/rocks/ + diff --git a/modules/ketcd/ketcd.lua b/modules/ketcd/ketcd.lua new file mode 100644 index 000000000..d4ee5053d --- /dev/null +++ b/modules/ketcd/ketcd.lua @@ -0,0 +1,24 @@ +--- @module ketcd +local ketcd = {} +local Etcd = require('etcd.luasocket') + +function ketcd.init(module) + print('wip') +end + +function ketcd.deinit(module) + print('wip') +end + +function ketcd.config(module, conf) + local cli, err = Etcd.new({ + peer = conf, + }); + ketcd._cli = cli +end + +function ketcd.layers(module) + return {} +end + +return ketcd diff --git a/modules/ketcd/ketcd.mk b/modules/ketcd/ketcd.mk new file mode 100644 index 000000000..3c45daf3b --- /dev/null +++ b/modules/ketcd/ketcd.mk @@ -0,0 +1 @@ +$(call make_lua_module,ketcd) diff --git a/modules/modules.mk b/modules/modules.mk index 2f5ea327d..26b8eb977 100644 --- a/modules/modules.mk +++ b/modules/modules.mk @@ -2,6 +2,11 @@ modules_TARGETS := hints \ cachectl +# List of Lua modules +ifeq ($(HAS_lua),yes) +modules_TARGETS += ketcd +endif + # List of Golang modules ifeq ($(HAS_gccgo),yes) modules_TARGETS += gostats @@ -12,6 +17,20 @@ define make_c_module $(eval $(call make_module,$(1),modules/$(1))) endef +# Make Lua module +define make_lua_module +$(eval $(call lua_target,$(1),modules/$(1))) +endef + +# Lua target definition +define lua_target +$(1) := $(2)/$(1).lua +$(1)-install: $(2)/$(1).lua + $(INSTALL) -d $(PREFIX)/$(MODULEDIR) + $(INSTALL) $$^ $(PREFIX)/$(MODULEDIR) +.PHONY: $(1) $(1)-install +endef + # Make Go module define make_go_module $(eval $(call go_target,$(1),modules/$(1)))