diff --git a/core/config.c b/core/config.c new file mode 100644 index 00000000..2a6a2790 --- /dev/null +++ b/core/config.c @@ -0,0 +1,33 @@ +#include + +/* + + pluggable configuration system + +*/ + +extern struct uwsgi_server uwsgi; + +struct uwsgi_configurator *uwsgi_register_configurator(char *name, void (*func)(char *, char **)) { + struct uwsgi_configurator *old_uc = NULL,*uc = uwsgi.configurators; + while(uc) { + if (!strcmp(uc->name, name)) { + return uc; + } + old_uc = uc; + uc = uc->next; + } + + uc = uwsgi_calloc(sizeof(struct uwsgi_configurator)); + uc->name = name; + uc->func = func; + + if (old_uc) { + old_uc->next = uc; + } + else { + uwsgi.configurators = uc; + } + + return uc; +} diff --git a/core/uwsgi.c b/core/uwsgi.c index d5044d71..51c4255f 100644 --- a/core/uwsgi.c +++ b/core/uwsgi.c @@ -70,6 +70,7 @@ static struct uwsgi_option uwsgi_base_options[] = { {"xmlconfig", required_argument, 'x', "load config from xml file", uwsgi_opt_load_xml, NULL, UWSGI_OPT_IMMEDIATE}, {"xml", required_argument, 'x', "load config from xml file", uwsgi_opt_load_xml, NULL, UWSGI_OPT_IMMEDIATE}, #endif + {"config", required_argument, 0, "load configuration using the pluggable system", uwsgi_opt_load_config, NULL, UWSGI_OPT_IMMEDIATE}, {"skip-zero", no_argument, 0, "skip check of file descriptor 0", uwsgi_opt_true, &uwsgi.skip_zero, 0}, @@ -3764,6 +3765,9 @@ void uwsgi_opt_load(char *opt, char *filename, void *none) { return; } #endif + + // fallback to pluggable system + uwsgi_opt_load_config(opt, filename, none); } void uwsgi_opt_logic(char *opt, char *arg, void *func) { @@ -3790,6 +3794,18 @@ void uwsgi_opt_load_ini(char *opt, char *filename, void *none) { uwsgi_ini_config(filename, uwsgi.magic_table); } +void uwsgi_opt_load_config(char *opt, char *filename, void *none) { + struct uwsgi_configurator *uc = uwsgi.configurators; + while(uc) { + if (uwsgi_endswith(filename, uc->name)) { + config_magic_table_fill(filename, uwsgi.magic_table); + uc->func(filename, uwsgi.magic_table); + return; + } + uc = uc->next; + } +} + #ifdef UWSGI_XML void uwsgi_opt_load_xml(char *opt, char *filename, void *none) { config_magic_table_fill(filename, uwsgi.magic_table); diff --git a/plugins/lua/lua_plugin.c b/plugins/lua/lua_plugin.c index 83d8671d..66802ed4 100644 --- a/plugins/lua/lua_plugin.c +++ b/plugins/lua/lua_plugin.c @@ -672,6 +672,54 @@ static uint16_t uwsgi_lua_rpc(void * func, uint8_t argc, char **argv, uint16_t a } +static void uwsgi_lua_configurator(char *filename, char *magic_table[]) { + size_t len = 0; + uwsgi_log_initial("[uWSGI] getting Lua configuration from %s\n", filename); + char *code = uwsgi_open_and_read(filename, &len, 1, magic_table); + lua_State *L = luaL_newstate(); + if (!L) { + uwsgi_log("unable to initialize Lua state for configuration\n"); + exit(1); + } + luaL_openlibs(L); + if (luaL_dostring(L, code) != 0) { + uwsgi_log("error running Lua configurator: %s\n", lua_tostring(L, -1)); + exit(1); + } + + if (!lua_istable(L, -1)) { + uwsgi_log("Lua configurator has to return a table !!!\n"); + exit(1); + } + + lua_pushnil(L); + // we always use uwsgi_str to avoid GC destroying our strings + // and to be able to call lua_close at the end + while (lua_next(L, -2) != 0) { + char *key = uwsgi_str((char *)lua_tostring(L, -2)); + if (lua_istable(L, -1)) { + lua_pushnil(L); + while (lua_next(L, -2) != 0) { + char *value = uwsgi_str((char *)lua_tostring(L, -1)); + add_exported_option(key, value, 0); + lua_pop(L, 1); + } + } + else { + char *value = uwsgi_str((char *)lua_tostring(L, -1)); + add_exported_option(key, value, 0); + } + lua_pop(L, 1); + } + + // this will destroy the whole Lua state + lua_close(L); +} + +static void uwsgi_register_lua_features() { + uwsgi_register_configurator(".lua", uwsgi_lua_configurator); +} + struct uwsgi_plugin lua_plugin = { @@ -688,5 +736,6 @@ struct uwsgi_plugin lua_plugin = { .code_string = uwsgi_lua_code_string, .rpc = uwsgi_lua_rpc, + .on_load = uwsgi_register_lua_features, }; diff --git a/uwsgi.h b/uwsgi.h index 84f074c0..eb296469 100644 --- a/uwsgi.h +++ b/uwsgi.h @@ -1506,6 +1506,14 @@ struct uwsgi_instance_status { int is_cleaning; }; +struct uwsgi_configurator { + char *name; + void (*func)(char *, char **); + struct uwsgi_configurator *next; +}; +struct uwsgi_configurator *uwsgi_register_configurator(char *, void (*)(char *, char **)); +void uwsgi_opt_load_config(char *, char *, void *); + #define uwsgi_instance_is_dying (uwsgi.status.gracefully_destroying || uwsgi.status.brutally_destroying) #define uwsgi_instance_is_reloading (uwsgi.status.gracefully_reloading || uwsgi.status.brutally_reloading) @@ -1517,6 +1525,7 @@ struct uwsgi_server { int hostname_len; int (*proto_hooks[UWSGI_PROTO_MAX_CHECK]) (struct wsgi_request *, char *, char *, uint16_t); + struct uwsgi_configurator *configurators; char **orig_argv; char **argv; diff --git a/uwsgiconfig.py b/uwsgiconfig.py index 40c0800a..0f566d91 100644 --- a/uwsgiconfig.py +++ b/uwsgiconfig.py @@ -457,7 +457,7 @@ class uConf(object): self.config.readfp(open_profile(filename)) self.gcc_list = ['core/utils', 'core/protocol', 'core/socket', 'core/logging', 'core/master', 'core/master_utils', 'core/emperor', 'core/notify', 'core/mule', 'core/subscription', 'core/stats', 'core/sendfile', 'core/async', 'core/master_checks', - 'core/offload', 'core/io', 'core/static', 'core/websockets', 'core/spooler', 'core/snmp', 'core/exceptions', + 'core/offload', 'core/io', 'core/static', 'core/websockets', 'core/spooler', 'core/snmp', 'core/exceptions', 'core/config', 'core/setup_utils', 'core/clock', 'core/init', 'core/buffer', 'core/reader', 'core/writer', 'core/alarm', 'core/plugins', 'core/lock', 'core/cache', 'core/daemons', 'core/errors', 'core/hash', 'core/master_events', 'core/queue', 'core/event', 'core/signal', 'core/strings', 'core/progress', 'core/timebomb', 'core/ini',