From 1245fba35bdd3f79d23c11f35fff05d734f74bd3 Mon Sep 17 00:00:00 2001 From: Mark Riddoch Date: Mon, 2 Jun 2014 17:10:05 +0100 Subject: [PATCH] Addition of the module info structure to allow module information to be extracted from the modules. This gives a way to verify the API that the module provides as well as the version of that API. The hope is that this will make it possible for MaxScale to detect out of date plugins and either adapt to use them or reject loading them. Also added the ability to set a release state on a per module basis. This allows for production ready and non-production ready plugins to be identified. --- server/core/load_utils.c | 54 ++++++++---- server/include/dcb.h | 8 ++ server/include/modinfo.h | 85 +++++++++++++++++++ server/include/modules.h | 3 + server/include/monitor.h | 6 ++ server/include/router.h | 7 ++ server/modules/monitor/galera_mon.c | 8 ++ server/modules/monitor/mysql_mon.c | 8 ++ server/modules/protocol/httpd.c | 8 ++ server/modules/protocol/mysql_backend.c | 8 ++ server/modules/protocol/mysql_client.c | 8 ++ server/modules/protocol/telnetd.c | 8 ++ server/modules/routing/debugcli.c | 9 ++ server/modules/routing/readconnroute.c | 8 ++ .../routing/readwritesplit/readwritesplit.c | 11 ++- server/modules/routing/testroute.c | 10 ++- 16 files changed, 232 insertions(+), 17 deletions(-) create mode 100644 server/include/modinfo.h diff --git a/server/core/load_utils.c b/server/core/load_utils.c index ba5507018..8bf157e9c 100644 --- a/server/core/load_utils.c +++ b/server/core/load_utils.c @@ -28,6 +28,7 @@ * 14/06/13 Mark Riddoch Updated to add call to ModuleInit if one is * defined in the loaded module. * Also updated to call fixed GetModuleObject + * 02/06/14 Mark Riddoch Addition of module info * * @endverbatim */ @@ -38,6 +39,7 @@ #include #include #include +#include #include #include @@ -47,10 +49,11 @@ static MODULES *registered = NULL; static MODULES *find_module(const char *module); static void register_module(const char *module, - const char *type, - void *dlhandle, - char *version, - void *modobj); + const char *type, + void *dlhandle, + char *version, + void *modobj, + MODULE_INFO *info); static void unregister_module(const char *module); char* get_maxscale_home(void) @@ -76,12 +79,13 @@ char* get_maxscale_home(void) void * load_module(const char *module, const char *type) { -char *home, *version; -char fname[MAXPATHLEN]; -void *dlhandle, *sym; -char *(*ver)(); -void *(*ep)(), *modobj; -MODULES *mod; +char *home, *version; +char fname[MAXPATHLEN]; +void *dlhandle, *sym; +char *(*ver)(); +void *(*ep)(), *modobj; +MODULES *mod; +MODULE_INFO *mod_info = NULL; if ((mod = find_module(module)) == NULL) { @@ -141,6 +145,11 @@ MODULES *mod; ModuleInit(); } + if ((sym = dlsym(dlhandle, "info")) != NULL) + { + mod_info = sym; + } + if ((sym = dlsym(dlhandle, "GetModuleObject")) == NULL) { LOGIF(LE, (skygw_log_write_flush( @@ -161,7 +170,7 @@ MODULES *mod; module, version, fname))); - register_module(module, type, dlhandle, version, modobj); + register_module(module, type, dlhandle, version, modobj, mod_info); } else { @@ -227,7 +236,7 @@ MODULES *mod = registered; * @param modobj The module object */ static void -register_module(const char *module, const char *type, void *dlhandle, char *version, void *modobj) +register_module(const char *module, const char *type, void *dlhandle, char *version, void *modobj, MODULE_INFO *mod_info) { MODULES *mod; @@ -239,6 +248,7 @@ MODULES *mod; mod->version = strdup(version); mod->modobj = modobj; mod->next = registered; + mod->info = mod_info; registered = mod; } @@ -303,11 +313,25 @@ dprintAllModules(DCB *dcb) { MODULES *ptr = registered; - dcb_printf(dcb, "%-15s | %-11s | Version\n", "Module Name", "Module Type"); - dcb_printf(dcb, "-----------------------------------------------------\n"); + dcb_printf(dcb, "%-15s | %-11s | Version | API | Status\n", "Module Name", "Module Type"); + dcb_printf(dcb, "--------------------------------------------------------------------------\n"); while (ptr) { - dcb_printf(dcb, "%-15s | %-11s | %s\n", ptr->module, ptr->type, ptr->version); + dcb_printf(dcb, "%-15s | %-11s | %-7s ", ptr->module, ptr->type, ptr->version); + if (ptr->info) + dcb_printf(dcb, "| %d.%d.%d | %s", + ptr->info->api_version.major, + ptr->info->api_version.minor, + ptr->info->api_version.patch, + ptr->info->status == MODULE_IN_DEVELOPMENT + ? "In Development" + : (ptr->info->status == MODULE_ALPHA_RELEASE + ? "Alpha" + : (ptr->info->status == MODULE_BETA_RELEASE + ? "Beta" + : (ptr->info->status == MODULE_GA + ? "GA" : "Unknown")))); + dcb_printf(dcb, "\n"); ptr = ptr->next; } } diff --git a/server/include/dcb.h b/server/include/dcb.h index e90a64856..49a262f73 100644 --- a/server/include/dcb.h +++ b/server/include/dcb.h @@ -19,6 +19,7 @@ */ #include #include +#include #include #include #include @@ -93,6 +94,13 @@ typedef struct gw_protocol { int (*session)(struct dcb *, void *); } GWPROTOCOL; +/** + * The GWPROTOCOL version data. The following should be updated whenever + * the GWPROTOCOL structure is changed. See the rules defined in modinfo.h + * that define how these numbers should change. + */ +#define GWPROTOCOL_VERSION {1, 0, 0} + /** * The statitics gathered on a descriptor control block */ diff --git a/server/include/modinfo.h b/server/include/modinfo.h new file mode 100644 index 000000000..c3c1e64da --- /dev/null +++ b/server/include/modinfo.h @@ -0,0 +1,85 @@ +#ifndef _MODINFO_H +#define _MODINFO_H +/* + * This file is distributed as part of MaxScale. It is free + * software: you can redistribute it and/or modify it under the terms of the + * GNU General Public License as published by the Free Software Foundation, + * version 2. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., 51 + * Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Copyright SkySQL Ab 2014 + */ + +/** + * @file modinfo.h The module information interface + * + * @verbatim + * Revision History + * + * Date Who Description + * 02/06/14 Mark Riddoch Initial implementation + * + * @endverbatim + */ + +/** + * The status of the module. This gives some idea of the module + * maturity. + */ +typedef enum { + MODULE_IN_DEVELOPMENT = 0, + MODULE_ALPHA_RELEASE, + MODULE_BETA_RELEASE, + MODULE_GA +} MODULE_STATUS; + +/** + * The API implemented by the module + */ +typedef enum { + MODULE_API_PROTOCOL = 0, + MODULE_API_ROUTER, + MODULE_API_MONITOR, + MODULE_API_FILTER, + MODULE_API_AUTHENTICATION +} MODULE_API; + +/** + * The module version structure. + * + * The rules for changing these values are: + * + * Any change that affects an inexisting call in the API in question, + * making the new API no longer compatible with the old, + * must increment the major version. + * + * Any change that adds to the API, but does not alter the existing API + * calls, must increment the minor version. + * + * Any change that is purely cosmetic and does not affect the calling + * conventions of the API must increment only the patch version number. + */ +typedef struct { + int major; + int minor; + int patch; +} MODULE_VERSION; + +/** + * The module information structure + */ +typedef struct { + MODULE_API modapi; + MODULE_STATUS status; + MODULE_VERSION api_version; + char *description; +} MODULE_INFO; +#endif diff --git a/server/include/modules.h b/server/include/modules.h index c90cf45a1..dc39983ac 100644 --- a/server/include/modules.h +++ b/server/include/modules.h @@ -18,6 +18,7 @@ * Copyright SkySQL Ab 2013 */ #include +#include /** * @file modules.h Utilities for loading modules @@ -39,6 +40,8 @@ typedef struct modules { char *version; /**< Module version */ void *handle; /**< The handle returned by dlopen */ void *modobj; /**< The module "object" this is the set of entry points */ + MODULE_INFO + *info; /**< The module information */ struct modules *next; /**< Next module in the linked list */ } MODULES; diff --git a/server/include/monitor.h b/server/include/monitor.h index 9ac453876..861c1c070 100644 --- a/server/include/monitor.h +++ b/server/include/monitor.h @@ -72,6 +72,12 @@ typedef struct { void (*replicationHeartbeat)(void *, int); } MONITOR_OBJECT; +/** + * The monitor API version number. Any change to the monitor module API + * must change these versions usign the rules defined in modinfo.h + */ +#define MONITOR_VERSION {1, 0, 0} + /** * Representation of the running monitor. */ diff --git a/server/include/router.h b/server/include/router.h index 004f91d51..ce8f547d8 100644 --- a/server/include/router.h +++ b/server/include/router.h @@ -78,6 +78,13 @@ typedef struct router_object { uint8_t (*getCapabilities)(ROUTER *instance, void* router_session); } ROUTER_OBJECT; +/** + * The router module API version. Any change that changes the router API + * must update these versions numbers in accordance with the rules in + * modinfo.h. + */ +#define ROUTER_VERSION { 1, 0, 0 } + typedef enum router_capability_t { RCAP_TYPE_UNDEFINED = 0, RCAP_TYPE_STMT_INPUT = (1 << 0), diff --git a/server/modules/monitor/galera_mon.c b/server/modules/monitor/galera_mon.c index 69bc38731..1493548d2 100644 --- a/server/modules/monitor/galera_mon.c +++ b/server/modules/monitor/galera_mon.c @@ -44,6 +44,7 @@ #include #include #include +#include extern int lm_enabled_logfiles_bitmask; @@ -51,6 +52,13 @@ static void monitorMain(void *); static char *version_str = "V1.2.0"; +MODULE_INFO info = { + MODULE_API_MONITOR, + MODULE_ALPHA_RELEASE, + MONITOR_VERSION, + "A Galera cluster monitor" +}; + static void *startMonitor(void *); static void stopMonitor(void *); static void registerServer(void *, SERVER *); diff --git a/server/modules/monitor/mysql_mon.c b/server/modules/monitor/mysql_mon.c index 96f842383..14b51ee29 100644 --- a/server/modules/monitor/mysql_mon.c +++ b/server/modules/monitor/mysql_mon.c @@ -48,6 +48,7 @@ #include #include #include +#include extern int lm_enabled_logfiles_bitmask; @@ -55,6 +56,13 @@ static void monitorMain(void *); static char *version_str = "V1.2.0"; +MODULE_INFO info = { + MODULE_API_MONITOR, + MODULE_ALPHA_RELEASE, + MONITOR_VERSION, + "A MySQL Master/Slave replication monitor" +}; + static void *startMonitor(void *); static void stopMonitor(void *); static void registerServer(void *, SERVER *); diff --git a/server/modules/protocol/httpd.c b/server/modules/protocol/httpd.c index f92e49598..7d06264b9 100644 --- a/server/modules/protocol/httpd.c +++ b/server/modules/protocol/httpd.c @@ -39,6 +39,14 @@ #include #include +#include + +MODULE_INFO info = { + MODULE_API_PROTOCOL, + MODULE_IN_DEVELOPMENT, + GWPROTOCOL_VERSION, + "An experimental HTTPD implementation for use in admnistration" +}; #define ISspace(x) isspace((int)(x)) #define HTTP_SERVER_STRING "Gateway(c) v.1.0.0" diff --git a/server/modules/protocol/mysql_backend.c b/server/modules/protocol/mysql_backend.c index efa92a71d..9dfa6e637 100644 --- a/server/modules/protocol/mysql_backend.c +++ b/server/modules/protocol/mysql_backend.c @@ -43,6 +43,14 @@ * 27/09/2013 Massimiliano Pinto Changed in gw_read_backend_event the check for dcb_read(), now is if rc < 0 * */ +#include + +MODULE_INFO info = { + MODULE_API_PROTOCOL, + MODULE_ALPHA_RELEASE, + GWPROTOCOL_VERSION, + "The MySQL to backend server protocol" +}; extern int lm_enabled_logfiles_bitmask; diff --git a/server/modules/protocol/mysql_client.c b/server/modules/protocol/mysql_client.c index bcd94e423..2f1a3b2c5 100644 --- a/server/modules/protocol/mysql_client.c +++ b/server/modules/protocol/mysql_client.c @@ -40,6 +40,14 @@ #include #include #include +#include + +MODULE_INFO info = { + MODULE_API_PROTOCOL, + MODULE_ALPHA_RELEASE, + GWPROTOCOL_VERSION, + "The client to MaxScale MySQL protocol implementation" +}; extern int lm_enabled_logfiles_bitmask; diff --git a/server/modules/protocol/telnetd.c b/server/modules/protocol/telnetd.c index f7d6c1815..651e979f0 100644 --- a/server/modules/protocol/telnetd.c +++ b/server/modules/protocol/telnetd.c @@ -36,6 +36,14 @@ #include #include #include +#include + +MODULE_INFO info = { + MODULE_API_PROTOCOL, + MODULE_ALPHA_RELEASE, + GWPROTOCOL_VERSION, + "A telnet deamon protocol for simple administration interface" +}; extern int lm_enabled_logfiles_bitmask; diff --git a/server/modules/routing/debugcli.c b/server/modules/routing/debugcli.c index 61e308a96..bf2404c08 100644 --- a/server/modules/routing/debugcli.c +++ b/server/modules/routing/debugcli.c @@ -35,6 +35,7 @@ #include #include #include +#include #include #include #include @@ -43,6 +44,14 @@ #include #include + +MODULE_INFO info = { + MODULE_API_ROUTER, + MODULE_ALPHA_RELEASE, + ROUTER_VERSION, + "The debug user interface" +}; + extern int lm_enabled_logfiles_bitmask; static char *version_str = "V1.1.1"; diff --git a/server/modules/routing/readconnroute.c b/server/modules/routing/readconnroute.c index 2bfba7efc..f1981c57a 100644 --- a/server/modules/routing/readconnroute.c +++ b/server/modules/routing/readconnroute.c @@ -79,6 +79,7 @@ #include #include #include +#include #include #include @@ -88,6 +89,13 @@ extern int lm_enabled_logfiles_bitmask; +MODULE_INFO info = { + MODULE_API_ROUTER, + MODULE_ALPHA_RELEASE, + ROUTER_VERSION, + "A connection based router to load balance based on connections" +}; + static char *version_str = "V1.0.2"; /* The router entry points */ diff --git a/server/modules/routing/readwritesplit/readwritesplit.c b/server/modules/routing/readwritesplit/readwritesplit.c index 5b855afe4..fca3bca92 100644 --- a/server/modules/routing/readwritesplit/readwritesplit.c +++ b/server/modules/routing/readwritesplit/readwritesplit.c @@ -30,6 +30,15 @@ #include #include #include +#include + +MODULE_INFO info = { + MODULE_API_ROUTER, + MODULE_ALPHA_RELEASE, + ROUTER_VERSION, + "A Read/Write splitting router for enhancement read scalability" +}; + extern int lm_enabled_logfiles_bitmask; @@ -2450,4 +2459,4 @@ static void rwsplit_process_options( } } } /*< for */ -} \ No newline at end of file +} diff --git a/server/modules/routing/testroute.c b/server/modules/routing/testroute.c index c0bd73fee..ce2ce2ca9 100644 --- a/server/modules/routing/testroute.c +++ b/server/modules/routing/testroute.c @@ -17,9 +17,17 @@ */ #include #include +#include static char *version_str = "V1.0.0"; +MODULE_INFO info = { + MODULE_API_ROUTER, + MODULE_IN_DEVELOPMENT, + ROUTER_VERSION, + "A test router - not for use in real systems" +}; + static ROUTER *createInstance(SERVICE *service, char **options); static void *newSession(ROUTER *instance, SESSION *session); static void closeSession(ROUTER *instance, void *session); @@ -145,4 +153,4 @@ static uint8_t getCapabilities( void* router_session) { return 0; -} \ No newline at end of file +}