Notification Service integration added
Notification Service integration added
This commit is contained in:
commit
7af2843bcb
@ -28,6 +28,13 @@ find_package(MySQLClient)
|
||||
find_package(MySQL)
|
||||
find_package(Pandoc)
|
||||
|
||||
# You can find the variables set by this in the FindCURL.cmake file
|
||||
# which is a default module in CMake.
|
||||
find_package(CURL)
|
||||
if(NOT CURL_FOUND)
|
||||
message(FATAL_ERROR "Failed to locate dependency: libcurl")
|
||||
endif()
|
||||
|
||||
set(CMAKE_INSTALL_RPATH ${CMAKE_INSTALL_RPATH}:${CMAKE_INSTALL_PREFIX}/lib:${CMAKE_INSTALL_PREFIX}/modules)
|
||||
|
||||
# Make sure the release notes for this release are present if it is a stable one
|
||||
@ -114,6 +121,7 @@ include_directories(server/include)
|
||||
include_directories(server/inih)
|
||||
include_directories(server/modules/include)
|
||||
include_directories(${CMAKE_BINARY_DIR}/server/include)
|
||||
include_directories(${CURL_INCLUDE_DIRS})
|
||||
|
||||
add_subdirectory(utils)
|
||||
add_subdirectory(log_manager)
|
||||
|
94
Documentation/Tutorials/Notification-Service.md
Normal file
94
Documentation/Tutorials/Notification-Service.md
Normal file
@ -0,0 +1,94 @@
|
||||
# MaxScale Notification Service and Feedback Support
|
||||
|
||||
Massimiliano Pinto
|
||||
|
||||
Last Updated: 10th March 2015
|
||||
|
||||
## Contents
|
||||
|
||||
## Document History
|
||||
|
||||
<table>
|
||||
<tr>
|
||||
<td>Date</td>
|
||||
<td>Change</td>
|
||||
<td>Who</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>10th March 2015</td>
|
||||
<td>Initial version</td>
|
||||
<td>Massimiliano Pinto</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
|
||||
## Overview
|
||||
|
||||
The purpose of Notification Service in MaxScale is for a customer registered for the service to receive update notices, security bulletins, fixes and workarounds that are tailored to the database server configuration.
|
||||
|
||||
## MaxScale Setup
|
||||
|
||||
MaxScale may collect the installed plugins and send the informations nightly, between 2:00 AM and 4:59 AM.
|
||||
|
||||
It tries to send data and if there is any failure (timeout, server is down, etc), the next retry is in 1800 seconds (30 minutes)
|
||||
|
||||
This feature is not enabled by default: MaxScale must be configured in [feedback] section:
|
||||
|
||||
|
||||
[feedback]
|
||||
feedback_enable=1
|
||||
feedback_url=https://mariadb.org/feedback_plugin/post
|
||||
feedback_user_info=x-y-z-w
|
||||
|
||||
The activation code that will be provided by MariaDB corp upon request by the customer and it shlud be put in feedback_user_info.
|
||||
|
||||
Example:
|
||||
feedback_user_info=0467009f-b04d-45b1-a77b-b6b2ec9c6cf4
|
||||
|
||||
|
||||
MaxScale generates the feedback report containing following information:
|
||||
|
||||
-The activation code used to enable feedback
|
||||
- MaxScale Version
|
||||
- An identifier of the MaxScale installation, i.e. the HEX encoding of SHA1 digest of the first network interface MAC address
|
||||
- Operating System (i.e Linux)
|
||||
- Operating Suystem Distribution (i.e. CentOS release 6.5 (Final))
|
||||
- All the modules in use in MaxScale and their API and version
|
||||
- MaxScale server UNIX_TIME at generation time
|
||||
|
||||
MaxScale shall send the generated feedback report to a feedback server specified in feedback_url
|
||||
|
||||
|
||||
## Manual Operation
|
||||
|
||||
If it’s not possible to send data due to firewall or security settings the report could be generated manually (feedback_user_info is required) via MaxAdmin
|
||||
|
||||
|
||||
MaxScale>show feedback report
|
||||
|
||||
|
||||
Report could be saved to report.txt file:
|
||||
|
||||
|
||||
maxadmin -uxxx -pyyy show feedbackreport > ./report.txt
|
||||
|
||||
curl -F data=@./report.txt https://mariadb.org/feedback_plugin/post
|
||||
|
||||
|
||||
Report Example:
|
||||
|
||||
FEEDBACK_SERVER_UID 6B5C44AEA73137D049B02E6D1C7629EF431A350F
|
||||
FEEDBACK_USER_INFO 0467009f-b04d-45b1-a77b-b6b2ec9c6cf4
|
||||
VERSION 1.0.6-unstable
|
||||
NOW 1425914890
|
||||
PRODUCT maxscale
|
||||
Uname_sysname Linux
|
||||
Uname_distribution CentOS release 6.5 (Final)
|
||||
module_maxscaled_type Protocol
|
||||
module_maxscaled_version V1.0.0
|
||||
module_maxscaled_api 1.0.0
|
||||
module_maxscaled_releasestatus GA
|
||||
module_telnetd_type Protocol
|
||||
module_telnetd_version V1.0.1
|
||||
module_telnetd_api 1.0.0
|
||||
module_telnetd_releasestatus GA
|
@ -1,14 +1,15 @@
|
||||
if(BUILD_TESTS)
|
||||
file(GLOB FULLCORE_SRC *.c)
|
||||
add_library(fullcore STATIC ${FULLCORE_SRC})
|
||||
target_link_libraries(fullcore log_manager utils pthread ${EMBEDDED_LIB} ssl aio rt crypt dl crypto inih z m stdc++)
|
||||
target_link_libraries(fullcore ${CURL_LIBRARIES} log_manager utils pthread ${EMBEDDED_LIB} ssl aio rt crypt dl crypto inih z m stdc++)
|
||||
endif()
|
||||
|
||||
add_executable(maxscale atomic.c buffer.c spinlock.c gateway.c
|
||||
gw_utils.c utils.c dcb.c load_utils.c session.c service.c server.c
|
||||
poll.c config.c users.c hashtable.c dbusers.c thread.c gwbitmask.c
|
||||
monitor.c adminusers.c secrets.c filter.c modutil.c hint.c
|
||||
housekeeper.c memlog.c resultset.c)
|
||||
target_link_libraries(maxscale ${EMBEDDED_LIB} log_manager utils ssl aio pthread crypt dl crypto inih z rt m stdc++)
|
||||
target_link_libraries(maxscale ${EMBEDDED_LIB} ${CURL_LIBRARIES} log_manager utils ssl aio pthread crypt dl crypto inih z rt m stdc++)
|
||||
install(TARGETS maxscale DESTINATION bin)
|
||||
|
||||
add_executable(maxkeys maxkeys.c secrets.c utils.c)
|
||||
|
@ -41,6 +41,7 @@
|
||||
* 30/10/14 Massimiliano Pinto Added disable_master_failback parameter
|
||||
* 07/11/14 Massimiliano Pinto Addition of monitor timeouts for connect/read/write
|
||||
* 20/02/15 Markus Mäkelä Added connection_timeout parameter for services
|
||||
* 05/03/15 Massimiliano Pinto Added notification_feedback support
|
||||
*
|
||||
* @endverbatim
|
||||
*/
|
||||
@ -55,9 +56,22 @@
|
||||
#include <server.h>
|
||||
#include <users.h>
|
||||
#include <monitor.h>
|
||||
#include <modules.h>
|
||||
#include <skygw_utils.h>
|
||||
#include <log_manager.h>
|
||||
#include <mysql.h>
|
||||
#include <sys/utsname.h>
|
||||
#include <sys/fcntl.h>
|
||||
#include <glob.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <net/if.h>
|
||||
#include <housekeeper.h>
|
||||
#include <notification.h>
|
||||
#include <unistd.h>
|
||||
#include <netinet/in.h>
|
||||
#include <string.h>
|
||||
#include <sys/utsname.h>
|
||||
|
||||
|
||||
/** Defined in log_manager.cc */
|
||||
extern int lm_enabled_logfiles_bitmask;
|
||||
@ -70,12 +84,19 @@ static int process_config_update(CONFIG_CONTEXT *);
|
||||
static void free_config_context(CONFIG_CONTEXT *);
|
||||
static char *config_get_value(CONFIG_PARAMETER *, const char *);
|
||||
static int handle_global_item(const char *, const char *);
|
||||
static int handle_feedback_item(const char *, const char *);
|
||||
static void global_defaults();
|
||||
static void feedback_defaults();
|
||||
static void check_config_objects(CONFIG_CONTEXT *context);
|
||||
static int internalService(char *router);
|
||||
int config_truth_value(char *str);
|
||||
static int internalService(char *router);
|
||||
int config_get_ifaddr(unsigned char *output);
|
||||
int config_get_release_string(char* release);
|
||||
FEEDBACK_CONF * config_get_feedback_data();
|
||||
|
||||
static char *config_file = NULL;
|
||||
static GATEWAY_CONF gateway;
|
||||
static FEEDBACK_CONF feedback;
|
||||
char *version_string = NULL;
|
||||
|
||||
|
||||
@ -121,6 +142,12 @@ CONFIG_PARAMETER *param, *p1;
|
||||
{
|
||||
return handle_global_item(name, value);
|
||||
}
|
||||
|
||||
if (strcasecmp(section, "feedback") == 0)
|
||||
{
|
||||
return handle_feedback_item(name, value);
|
||||
}
|
||||
|
||||
/*
|
||||
* If we already have some parameters for the object
|
||||
* add the parameters to that object. If not create
|
||||
@ -192,6 +219,7 @@ int rval;
|
||||
}
|
||||
|
||||
global_defaults();
|
||||
feedback_defaults();
|
||||
|
||||
config.object = "";
|
||||
config.next = NULL;
|
||||
@ -280,7 +308,7 @@ int error_count = 0;
|
||||
char *auth;
|
||||
char *enable_root_user;
|
||||
char *connection_timeout;
|
||||
char *auth_all_servers;
|
||||
char *auth_all_servers;
|
||||
char *strip_db_esc;
|
||||
char *weightby;
|
||||
char *version_string;
|
||||
@ -296,19 +324,19 @@ int error_count = 0;
|
||||
"enable_root_user");
|
||||
|
||||
connection_timeout =
|
||||
config_get_value(
|
||||
obj->parameters,
|
||||
"connection_timeout");
|
||||
config_get_value(
|
||||
obj->parameters,
|
||||
"connection_timeout");
|
||||
|
||||
auth_all_servers =
|
||||
config_get_value(
|
||||
obj->parameters,
|
||||
"auth_all_servers");
|
||||
auth_all_servers =
|
||||
config_get_value(
|
||||
obj->parameters,
|
||||
"auth_all_servers");
|
||||
|
||||
strip_db_esc =
|
||||
config_get_value(
|
||||
obj->parameters,
|
||||
"strip_db_esc");
|
||||
config_get_value(
|
||||
obj->parameters,
|
||||
"strip_db_esc");
|
||||
|
||||
allow_localhost_match_wildcard_host =
|
||||
config_get_value(obj->parameters,
|
||||
@ -364,12 +392,14 @@ int error_count = 0;
|
||||
obj->element,
|
||||
atoi(connection_timeout));
|
||||
|
||||
if(auth_all_servers)
|
||||
serviceAuthAllServers(obj->element,
|
||||
config_truth_value(auth_all_servers));
|
||||
if(auth_all_servers)
|
||||
serviceAuthAllServers(obj->element,
|
||||
config_truth_value(auth_all_servers));
|
||||
|
||||
if(strip_db_esc)
|
||||
serviceStripDbEsc(obj->element,
|
||||
config_truth_value(strip_db_esc));
|
||||
serviceStripDbEsc(obj->element,
|
||||
config_truth_value(strip_db_esc));
|
||||
|
||||
if (weightby)
|
||||
serviceWeightBy(obj->element, weightby);
|
||||
|
||||
@ -751,7 +781,7 @@ int error_count = 0;
|
||||
/* if id is not set, do it now */
|
||||
if (gateway.id == 0) {
|
||||
setipaddress(&serv_addr.sin_addr, (address == NULL) ? "0.0.0.0" : address);
|
||||
gateway.id = (unsigned long) (serv_addr.sin_addr.s_addr + port + getpid());
|
||||
gateway.id = (unsigned long) (serv_addr.sin_addr.s_addr + atoi(port) + getpid());
|
||||
}
|
||||
|
||||
if (service && socket && protocol) {
|
||||
@ -1214,6 +1244,16 @@ config_pollsleep()
|
||||
return gateway.pollsleep;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the feedback config data pointer
|
||||
*
|
||||
* @return The feedback config data pointer
|
||||
*/
|
||||
FEEDBACK_CONF *
|
||||
config_get_feedback_data()
|
||||
{
|
||||
return &feedback;
|
||||
}
|
||||
|
||||
static struct {
|
||||
char *logname;
|
||||
@ -1249,8 +1289,8 @@ int i;
|
||||
}
|
||||
else if (strcmp(name, "ms_timestamp") == 0)
|
||||
{
|
||||
skygw_set_highp(atoi(value));
|
||||
}
|
||||
skygw_set_highp(atoi(value));
|
||||
}
|
||||
else
|
||||
{
|
||||
for (i = 0; lognames[i].logname; i++)
|
||||
@ -1267,12 +1307,48 @@ int i;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Configuration handler for items in the feedback [feedback] section
|
||||
*
|
||||
* @param name The item name
|
||||
* @param value The item value
|
||||
* @return 0 on error
|
||||
*/
|
||||
static int
|
||||
handle_feedback_item(const char *name, const char *value)
|
||||
{
|
||||
int i;
|
||||
if (strcmp(name, "feedback_enable") == 0)
|
||||
{
|
||||
feedback.feedback_enable = config_truth_value((char *)value);
|
||||
}
|
||||
else if (strcmp(name, "feedback_user_info") == 0)
|
||||
{
|
||||
feedback.feedback_user_info = strdup(value);
|
||||
}
|
||||
else if (strcmp(name, "feedback_url") == 0)
|
||||
{
|
||||
feedback.feedback_url = strdup(value);
|
||||
}
|
||||
if (strcmp(name, "feedback_timeout") == 0)
|
||||
{
|
||||
feedback.feedback_timeout = atoi(value);
|
||||
}
|
||||
if (strcmp(name, "feedback_connect_timeout") == 0)
|
||||
{
|
||||
feedback.feedback_connect_timeout = atoi(value);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the defaults for the global configuration options
|
||||
*/
|
||||
static void
|
||||
global_defaults()
|
||||
{
|
||||
uint8_t mac_addr[6]="";
|
||||
struct utsname uname_data;
|
||||
gateway.n_threads = 1;
|
||||
gateway.n_nbpoll = DEFAULT_NBPOLLS;
|
||||
gateway.pollsleep = DEFAULT_POLLSLEEP;
|
||||
@ -1281,6 +1357,41 @@ global_defaults()
|
||||
else
|
||||
gateway.version_string = NULL;
|
||||
gateway.id=0;
|
||||
|
||||
/* get release string */
|
||||
if(!config_get_release_string(gateway.release_string))
|
||||
sprintf(gateway.release_string,"undefined");
|
||||
|
||||
/* get first mac_address in SHA1 */
|
||||
if(config_get_ifaddr(mac_addr)) {
|
||||
gw_sha1_str(mac_addr, 6, gateway.mac_sha1);
|
||||
} else {
|
||||
memset(gateway.mac_sha1, '\0', sizeof(gateway.mac_sha1));
|
||||
memcpy(gateway.mac_sha1, "MAC-undef", 9);
|
||||
}
|
||||
|
||||
/* get uname info */
|
||||
if (uname(&uname_data))
|
||||
strcpy(gateway.sysname, "undefined");
|
||||
else
|
||||
strncpy(gateway.sysname, uname_data.sysname, _SYSNAME_STR_LENGTH);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the defaults for the feedback configuration options
|
||||
*/
|
||||
static void
|
||||
feedback_defaults()
|
||||
{
|
||||
feedback.feedback_enable = 0;
|
||||
feedback.feedback_user_info = NULL;
|
||||
feedback.feedback_last_action = _NOTIFICATION_SEND_PENDING;
|
||||
feedback.feedback_timeout = _NOTIFICATION_OPERATION_TIMEOUT;
|
||||
feedback.feedback_connect_timeout = _NOTIFICATION_CONNECT_TIMEOUT;
|
||||
feedback.feedback_url = NULL;
|
||||
feedback.release_info = gateway.release_string;
|
||||
feedback.sysname = gateway.sysname;
|
||||
feedback.mac_sha1 = gateway.mac_sha1;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1326,24 +1437,23 @@ SERVER *server;
|
||||
|
||||
char *connection_timeout;
|
||||
|
||||
char* auth_all_servers;
|
||||
char* auth_all_servers;
|
||||
char* strip_db_esc;
|
||||
char* max_slave_conn_str;
|
||||
char* max_slave_rlag_str;
|
||||
char* max_slave_conn_str;
|
||||
char* max_slave_rlag_str;
|
||||
char *version_string;
|
||||
char *allow_localhost_match_wildcard_host;
|
||||
|
||||
enable_root_user = config_get_value(obj->parameters, "enable_root_user");
|
||||
|
||||
connection_timeout = config_get_value(obj->parameters, "connection_timeout");
|
||||
|
||||
user = config_get_value(obj->parameters,
|
||||
"user");
|
||||
user = config_get_value(obj->parameters,
|
||||
"user");
|
||||
auth = config_get_value(obj->parameters,
|
||||
"passwd");
|
||||
"passwd");
|
||||
|
||||
auth_all_servers = config_get_value(obj->parameters, "auth_all_servers");
|
||||
strip_db_esc = config_get_value(obj->parameters, "strip_db_esc");
|
||||
auth_all_servers = config_get_value(obj->parameters, "auth_all_servers");
|
||||
strip_db_esc = config_get_value(obj->parameters, "strip_db_esc");
|
||||
version_string = config_get_value(obj->parameters, "version_string");
|
||||
allow_localhost_match_wildcard_host = config_get_value(obj->parameters, "localhost_match_wildcard_host");
|
||||
|
||||
@ -1476,13 +1586,12 @@ SERVER *server;
|
||||
char *enable_root_user;
|
||||
char *connection_timeout;
|
||||
char *allow_localhost_match_wildcard_host;
|
||||
char *auth_all_servers;
|
||||
char *strip_db_esc;
|
||||
char *auth_all_servers;
|
||||
char *strip_db_esc;
|
||||
|
||||
enable_root_user =
|
||||
config_get_value(obj->parameters,
|
||||
"enable_root_user");
|
||||
|
||||
|
||||
connection_timeout = config_get_value(obj->parameters,
|
||||
"connection_timeout");
|
||||
@ -1495,10 +1604,9 @@ SERVER *server;
|
||||
"strip_db_esc");
|
||||
|
||||
allow_localhost_match_wildcard_host =
|
||||
|
||||
config_get_value(obj->parameters, "localhost_match_wildcard_host");
|
||||
|
||||
user = config_get_value(obj->parameters,
|
||||
user = config_get_value(obj->parameters,
|
||||
"user");
|
||||
auth = config_get_value(obj->parameters,
|
||||
"passwd");
|
||||
@ -1928,3 +2036,219 @@ int i;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
/**
|
||||
* Get the MAC address of first network interface
|
||||
*
|
||||
* and fill the provided allocated buffer with SHA1 encoding
|
||||
* @param output Allocated 6 bytes buffer
|
||||
* @return 1 on success, 0 on failure
|
||||
*
|
||||
*/
|
||||
int
|
||||
config_get_ifaddr(unsigned char *output)
|
||||
{
|
||||
struct ifreq ifr;
|
||||
struct ifconf ifc;
|
||||
char buf[1024];
|
||||
struct ifreq* it;
|
||||
struct ifreq* end;
|
||||
int success = 0;
|
||||
|
||||
int sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP);
|
||||
if (sock == -1) {
|
||||
return 0;
|
||||
};
|
||||
|
||||
ifc.ifc_len = sizeof(buf);
|
||||
ifc.ifc_buf = buf;
|
||||
if (ioctl(sock, SIOCGIFCONF, &ifc) == -1) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
it = ifc.ifc_req;
|
||||
end = it + (ifc.ifc_len / sizeof(struct ifreq));
|
||||
|
||||
for (; it != end; ++it) {
|
||||
strcpy(ifr.ifr_name, it->ifr_name);
|
||||
if (ioctl(sock, SIOCGIFFLAGS, &ifr) == 0) {
|
||||
if (! (ifr.ifr_flags & IFF_LOOPBACK)) { /* don't count loopback */
|
||||
if (ioctl(sock, SIOCGIFHWADDR, &ifr) == 0) {
|
||||
success = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (success)
|
||||
memcpy(output, ifr.ifr_hwaddr.sa_data, 6);
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the linux distribution info
|
||||
*
|
||||
* @param release The allocated buffer where
|
||||
* the found distribution is copied into.
|
||||
* @return 1 on success, 0 on failure
|
||||
*
|
||||
*/
|
||||
int
|
||||
config_get_release_string(char* release)
|
||||
{
|
||||
const char *masks[]= {
|
||||
"/etc/*-version", "/etc/*-release",
|
||||
"/etc/*_version", "/etc/*_release"
|
||||
};
|
||||
|
||||
bool have_distribution;
|
||||
char distribution[_RELEASE_STR_LENGTH]="";
|
||||
int fd;
|
||||
int i;
|
||||
char *to;
|
||||
|
||||
have_distribution= false;
|
||||
|
||||
/* get data from lsb-release first */
|
||||
if ((fd= open("/etc/lsb-release", O_RDONLY)) != -1)
|
||||
{
|
||||
/* LSB-compliant distribution! */
|
||||
size_t len= read(fd, (char*)distribution, sizeof(distribution)-1);
|
||||
close(fd);
|
||||
if (len != (size_t)-1)
|
||||
{
|
||||
distribution[len]= 0;
|
||||
char *found= strstr(distribution, "DISTRIB_DESCRIPTION=");
|
||||
if (found)
|
||||
{
|
||||
have_distribution = true;
|
||||
char *end = strstr(found, "\n");
|
||||
if (end == NULL)
|
||||
end = distribution + len;
|
||||
found += 20;
|
||||
|
||||
if (*found == '"' && end[-1] == '"')
|
||||
{
|
||||
found++;
|
||||
end--;
|
||||
}
|
||||
*end = 0;
|
||||
|
||||
to = strcpy(distribution, "lsb: ");
|
||||
memmove(to, found, end - found + 1);
|
||||
|
||||
strncpy(release, to, _RELEASE_STR_LENGTH);
|
||||
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* if not an LSB-compliant distribution */
|
||||
for (i= 0; !have_distribution && i < 4; i++)
|
||||
{
|
||||
glob_t found;
|
||||
char *new_to;
|
||||
|
||||
if (glob(masks[i], GLOB_NOSORT, NULL, &found) == 0)
|
||||
{
|
||||
int fd;
|
||||
int k = 0;
|
||||
int skipindex = 0;
|
||||
int startindex = 0;
|
||||
|
||||
for (k = 0; k< found.gl_pathc; k++) {
|
||||
if (strcmp(found.gl_pathv[k], "/etc/lsb-release") == 0) {
|
||||
skipindex = k;
|
||||
}
|
||||
}
|
||||
|
||||
if ( skipindex == 0)
|
||||
startindex++;
|
||||
|
||||
if ((fd= open(found.gl_pathv[startindex], O_RDONLY)) != -1)
|
||||
{
|
||||
/*
|
||||
+5 and -8 below cut the file name part out of the
|
||||
full pathname that corresponds to the mask as above.
|
||||
*/
|
||||
new_to = strcpy(distribution, found.gl_pathv[0] + 5);
|
||||
new_to += 8;
|
||||
*new_to++ = ':';
|
||||
*new_to++ = ' ';
|
||||
|
||||
size_t to_len= distribution + sizeof(distribution) - 1 - new_to;
|
||||
size_t len= read(fd, (char*)new_to, to_len);
|
||||
|
||||
close(fd);
|
||||
|
||||
if (len != (size_t)-1)
|
||||
{
|
||||
new_to[len]= 0;
|
||||
char *end= strstr(new_to, "\n");
|
||||
if (end)
|
||||
*end= 0;
|
||||
|
||||
have_distribution= true;
|
||||
strncpy(release, new_to, _RELEASE_STR_LENGTH);
|
||||
}
|
||||
}
|
||||
}
|
||||
globfree(&found);
|
||||
}
|
||||
|
||||
if (have_distribution)
|
||||
return 1;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add the 'send_feedback' task to the task list
|
||||
*/
|
||||
void
|
||||
config_enable_feedback_task(void) {
|
||||
FEEDBACK_CONF *cfg = config_get_feedback_data();
|
||||
int url_set = 0;
|
||||
int user_info_set = 0;
|
||||
int enable_set = cfg->feedback_enable;
|
||||
|
||||
url_set = cfg->feedback_url != NULL && strlen(cfg->feedback_url);
|
||||
user_info_set = cfg->feedback_user_info != NULL && strlen(cfg->feedback_user_info);
|
||||
|
||||
if (enable_set && url_set && user_info_set) {
|
||||
/* Add the task to the tasl list */
|
||||
if (hktask_add("send_feedback", module_feedback_send, cfg, 1800)) {
|
||||
|
||||
LOGIF(LM, (skygw_log_write_flush(
|
||||
LOGFILE_MESSAGE,
|
||||
"Notification service feedback task started: URL=%s, User-Info=%s, Frequency %u seconds",
|
||||
cfg->feedback_url,
|
||||
cfg->feedback_user_info,
|
||||
1800)));
|
||||
}
|
||||
} else {
|
||||
if (enable_set) {
|
||||
LOGIF(LE, (skygw_log_write_flush(
|
||||
LOGFILE_ERROR,
|
||||
"Error: Notification service feedback cannot start: feedback_enable=1 but"
|
||||
" some required parameters are not set: %s%s%s",
|
||||
url_set == 0 ? "feedback_url is not set" : "", (user_info_set == 0 && url_set == 0) ? ", " : "", user_info_set == 0 ? "feedback_user_info is not set" : "")));
|
||||
} else {
|
||||
LOGIF(LT, (skygw_log_write_flush(
|
||||
LOGFILE_TRACE,
|
||||
"Notification service feedback is not enabled")));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the 'send_feedback' task
|
||||
*/
|
||||
void
|
||||
config_disable_feedback_task(void) {
|
||||
hktask_remove("send_feedback");
|
||||
}
|
||||
|
@ -23,12 +23,13 @@
|
||||
* @verbatim
|
||||
* Revision History
|
||||
*
|
||||
* Date Who Description
|
||||
* 13/06/13 Mark Riddoch Initial implementation
|
||||
* 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
|
||||
* Date Who Description
|
||||
* 13/06/13 Mark Riddoch Initial implementation
|
||||
* 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
|
||||
* 26/02/15 Massimiliano Pinto Addition of module_feedback_send
|
||||
*
|
||||
* @endverbatim
|
||||
*/
|
||||
@ -42,6 +43,11 @@
|
||||
#include <modinfo.h>
|
||||
#include <skygw_utils.h>
|
||||
#include <log_manager.h>
|
||||
#include <version.h>
|
||||
#include <notification.h>
|
||||
#include <curl/curl.h>
|
||||
#include <sys/utsname.h>
|
||||
#include <openssl/sha.h>
|
||||
|
||||
/** Defined in log_manager.cc */
|
||||
extern int lm_enabled_logfiles_bitmask;
|
||||
@ -58,6 +64,44 @@ static void register_module(const char *module,
|
||||
void *modobj,
|
||||
MODULE_INFO *info);
|
||||
static void unregister_module(const char *module);
|
||||
int module_create_feedback_report(GWBUF **buffer, MODULES *modules, FEEDBACK_CONF *cfg);
|
||||
|
||||
struct MemoryStruct {
|
||||
char *data;
|
||||
size_t size;
|
||||
};
|
||||
|
||||
/**
|
||||
* Callback write routine for curl library, getting remote server reply
|
||||
*
|
||||
* @param contents New data to add
|
||||
* @param size Data size
|
||||
* @param nmemb Elements in the buffer
|
||||
* @param userp Pointer to the buffer
|
||||
* @return 0 on failure, memory size on success
|
||||
*
|
||||
*/
|
||||
static size_t
|
||||
WriteMemoryCallback(void *contents, size_t size, size_t nmemb, void *userp)
|
||||
{
|
||||
size_t realsize = size * nmemb;
|
||||
struct MemoryStruct *mem = (struct MemoryStruct *)userp;
|
||||
|
||||
mem->data = realloc(mem->data, mem->size + realsize + 1);
|
||||
if(mem->data == NULL) {
|
||||
/* out of memory! */
|
||||
LOGIF(LE, (skygw_log_write_flush(
|
||||
LOGFILE_ERROR,
|
||||
"Error in module_feedback_send(), not enough memory for realloc")));
|
||||
return 0;
|
||||
}
|
||||
|
||||
memcpy(&(mem->data[mem->size]), contents, realsize);
|
||||
mem->size += realsize;
|
||||
mem->data[mem->size] = 0;
|
||||
|
||||
return realsize;
|
||||
}
|
||||
|
||||
char* get_maxscale_home(void)
|
||||
{
|
||||
@ -409,6 +453,29 @@ MODULES *ptr = registered;
|
||||
dcb_printf(dcb, "----------------+-------------+---------+-------+-------------------------\n\n");
|
||||
}
|
||||
|
||||
/**
|
||||
* Print Modules to a DCB
|
||||
*
|
||||
* Diagnostic routine to display all the loaded modules
|
||||
*/
|
||||
void
|
||||
moduleShowFeedbackReport(DCB *dcb)
|
||||
{
|
||||
GWBUF *buffer;
|
||||
MODULES *modules_list = registered;
|
||||
FEEDBACK_CONF *feedback_config = config_get_feedback_data();
|
||||
|
||||
if (!module_create_feedback_report(&buffer, modules_list, feedback_config)) {
|
||||
LOGIF(LE, (skygw_log_write_flush(
|
||||
LOGFILE_ERROR,
|
||||
"Error in module_create_feedback_report(): gwbuf_alloc() failed to allocate memory")));
|
||||
|
||||
return;
|
||||
}
|
||||
dcb_printf(dcb, (char *)GWBUF_DATA(buffer));
|
||||
gwbuf_free(buffer);
|
||||
}
|
||||
|
||||
/**
|
||||
* Provide a row to the result set that defines the set of modules
|
||||
*
|
||||
@ -485,3 +552,316 @@ int *data;
|
||||
|
||||
return set;
|
||||
}
|
||||
|
||||
/**
|
||||
* Send loaded modules info to notification service
|
||||
*
|
||||
* @param data The configuration details of notification service
|
||||
*/
|
||||
void
|
||||
module_feedback_send(void* data) {
|
||||
MODULES *modules_list = registered;
|
||||
CURL *curl = NULL;
|
||||
CURLcode res;
|
||||
struct curl_httppost *formpost=NULL;
|
||||
struct curl_httppost *lastptr=NULL;
|
||||
GWBUF *buffer = NULL;
|
||||
void *data_ptr=NULL;
|
||||
long http_code = 0;
|
||||
struct MemoryStruct chunk;
|
||||
int last_action = _NOTIFICATION_SEND_PENDING;
|
||||
time_t now;
|
||||
struct tm *now_tm;
|
||||
int hour;
|
||||
int n_mod=0;
|
||||
char hex_setup_info[2 * SHA_DIGEST_LENGTH + 1]="";
|
||||
|
||||
now = time(NULL);
|
||||
now_tm = localtime(&now);
|
||||
hour = now_tm->tm_hour;
|
||||
|
||||
FEEDBACK_CONF *feedback_config = (FEEDBACK_CONF *) data;
|
||||
|
||||
/* Configuration check */
|
||||
|
||||
if (feedback_config->feedback_enable == 0 || feedback_config->feedback_url == NULL || feedback_config->feedback_user_info == NULL) {
|
||||
LOGIF(LE, (skygw_log_write_flush(
|
||||
LOGFILE_ERROR,
|
||||
"Error in module_feedback_send(): some mandatory parameters are not set"
|
||||
" feedback_enable=%u, feedback_url=%s, feedback_user_info=%s",
|
||||
feedback_config->feedback_enable,
|
||||
feedback_config->feedback_url == NULL ? "NULL" : feedback_config->feedback_url,
|
||||
feedback_config->feedback_user_info == NULL ? "NULL" : feedback_config->feedback_user_info)));
|
||||
|
||||
feedback_config->feedback_last_action = _NOTIFICATION_SEND_ERROR;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Task runs nightly, from 2 AM to 4 AM
|
||||
*
|
||||
* If it's done in that time interval, it will be skipped
|
||||
*/
|
||||
|
||||
if (hour > 4 || hour < 2) {
|
||||
/* It's not the rigt time, mark it as to be done and return */
|
||||
feedback_config->feedback_last_action = _NOTIFICATION_SEND_PENDING;
|
||||
|
||||
LOGIF(LT, (skygw_log_write_flush(
|
||||
LOGFILE_TRACE,
|
||||
"module_feedback_send(): execution skipped, current hour [%d]"
|
||||
" is not within the proper interval (from 2 AM to 4 AM)",
|
||||
hour)));
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/* Time to run the task: if a previous run was succesfull skip next runs */
|
||||
if (feedback_config->feedback_last_action == _NOTIFICATION_SEND_OK) {
|
||||
/* task was done before, return */
|
||||
|
||||
LOGIF(LT, (skygw_log_write_flush(
|
||||
LOGFILE_TRACE,
|
||||
"module_feedback_send(): execution skipped because of previous succesful run: hour is [%d], last_action [%d]",
|
||||
hour, feedback_config->feedback_last_action)));
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
LOGIF(LT, (skygw_log_write_flush(
|
||||
LOGFILE_TRACE,
|
||||
"module_feedback_send(): task now runs: hour is [%d], last_action [%d]",
|
||||
hour, feedback_config->feedback_last_action)));
|
||||
|
||||
|
||||
/* allocate first memory chunck for httpd servr reply */
|
||||
chunk.data = malloc(1); /* will be grown as needed by the realloc above */
|
||||
chunk.size = 0; /* no data at this point */
|
||||
|
||||
if (!module_create_feedback_report(&buffer, modules_list, feedback_config)) {
|
||||
LOGIF(LE, (skygw_log_write_flush(
|
||||
LOGFILE_ERROR,
|
||||
"Error in module_create_feedback_report(): gwbuf_alloc() failed to allocate memory")));
|
||||
|
||||
feedback_config->feedback_last_action = _NOTIFICATION_SEND_ERROR;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
/* Initializing curl library for data send via HTTP */
|
||||
curl_global_init(CURL_GLOBAL_DEFAULT);
|
||||
|
||||
curl = curl_easy_init();
|
||||
|
||||
if (curl) {
|
||||
char error_message[CURL_ERROR_SIZE]="";
|
||||
|
||||
curl_easy_setopt(curl, CURLOPT_ERRORBUFFER, error_message);
|
||||
curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1);
|
||||
curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, feedback_config->feedback_connect_timeout);
|
||||
curl_easy_setopt(curl, CURLOPT_TIMEOUT, feedback_config->feedback_timeout);
|
||||
|
||||
/* curl API call for data send via HTTP POST using a "file" type input */
|
||||
curl_formadd(&formpost,
|
||||
&lastptr,
|
||||
CURLFORM_COPYNAME, "data",
|
||||
CURLFORM_BUFFER, "report.txt",
|
||||
CURLFORM_BUFFERPTR, (char *)GWBUF_DATA(buffer),
|
||||
CURLFORM_BUFFERLENGTH, strlen((char *)GWBUF_DATA(buffer)),
|
||||
CURLFORM_CONTENTTYPE, "text/plain",
|
||||
CURLFORM_END);
|
||||
|
||||
curl_easy_setopt(curl, CURLOPT_HEADER, 1);
|
||||
|
||||
/* some servers don't like requests that are made without a user-agent field, so we provide one */
|
||||
curl_easy_setopt(curl, CURLOPT_USERAGENT, "MaxScale-agent/http-1.0");
|
||||
/* Force HTTP/1.0 */
|
||||
curl_easy_setopt(curl, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0);
|
||||
|
||||
curl_easy_setopt(curl, CURLOPT_URL, feedback_config->feedback_url);
|
||||
curl_easy_setopt(curl, CURLOPT_HTTPPOST, formpost);
|
||||
|
||||
#ifdef SKIP_PEER_VERIFICATION
|
||||
/*
|
||||
* This makes the connection A LOT LESS SECURE.
|
||||
*/
|
||||
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L);
|
||||
#endif
|
||||
|
||||
#ifdef SKIP_HOSTNAME_VERIFICATION
|
||||
/*
|
||||
* this will make the connection less secure.
|
||||
*/
|
||||
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0L);
|
||||
#endif
|
||||
|
||||
/* send all data to this function */
|
||||
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteMemoryCallback);
|
||||
|
||||
/* we pass our 'chunk' struct to the callback function */
|
||||
curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)&chunk);
|
||||
|
||||
/* Perform the request, res will get the return code */
|
||||
res = curl_easy_perform(curl);
|
||||
|
||||
/* Check for errors */
|
||||
if(res != CURLE_OK) {
|
||||
last_action = _NOTIFICATION_SEND_ERROR;
|
||||
|
||||
LOGIF(LE, (skygw_log_write_flush(
|
||||
LOGFILE_ERROR,
|
||||
"Error: module_feedback_send(), curl call for [%s] failed due: %s, %s",
|
||||
feedback_config->feedback_url,
|
||||
curl_easy_strerror(res),
|
||||
error_message)));
|
||||
} else {
|
||||
curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &http_code);
|
||||
}
|
||||
|
||||
if (http_code == 302) {
|
||||
char *from = strstr(chunk.data, "<h1>ok</h1>");
|
||||
if (from) {
|
||||
last_action = _NOTIFICATION_SEND_OK;
|
||||
} else {
|
||||
last_action = _NOTIFICATION_SEND_ERROR;
|
||||
}
|
||||
} else {
|
||||
last_action = _NOTIFICATION_SEND_ERROR;
|
||||
LOGIF(LE, (skygw_log_write_flush(
|
||||
LOGFILE_ERROR,
|
||||
"Error in module_feedback_send(), Bad HTTP Code from remote server: %lu",
|
||||
http_code)));
|
||||
}
|
||||
} else {
|
||||
LOGIF(LE, (skygw_log_write_flush(
|
||||
LOGFILE_ERROR,
|
||||
"Error in module_feedback_send(), curl object not initialized")));
|
||||
last_action = _NOTIFICATION_SEND_ERROR;
|
||||
}
|
||||
|
||||
/* update last action in the config struct */
|
||||
feedback_config->feedback_last_action = last_action;
|
||||
|
||||
LOGIF(LT, (skygw_log_write_flush(
|
||||
LOGFILE_TRACE,
|
||||
"module_feedback_send(): task run result: hour is [%d], last_action [%d], HTTP code [%d]",
|
||||
hour, feedback_config->feedback_last_action, http_code)));
|
||||
|
||||
if (chunk.data)
|
||||
free(chunk.data);
|
||||
|
||||
if (buffer)
|
||||
gwbuf_free(buffer);
|
||||
|
||||
if (curl) {
|
||||
curl_easy_cleanup(curl);
|
||||
curl_formfree(formpost);
|
||||
}
|
||||
|
||||
curl_global_cleanup();
|
||||
}
|
||||
|
||||
/**
|
||||
* Create the feedback report as string.
|
||||
* I t could be sent to notification service
|
||||
* or just printed via maxadmin/telnet
|
||||
*
|
||||
* @param buffe The pointr for GWBUF allocation, to be freed by the caller
|
||||
* @param modules The mouleds list
|
||||
* @param cfg The feedback configuration
|
||||
* @return 0 on failure, 1 on success
|
||||
*
|
||||
*/
|
||||
|
||||
int
|
||||
module_create_feedback_report(GWBUF **buffer, MODULES *modules, FEEDBACK_CONF *cfg) {
|
||||
|
||||
MODULES *ptr = modules;
|
||||
int n_mod = 0;
|
||||
char *data_ptr=NULL;
|
||||
char hex_setup_info[2 * SHA_DIGEST_LENGTH + 1]="";
|
||||
time_t now;
|
||||
struct tm *now_tm;
|
||||
int report_max_bytes=0;
|
||||
|
||||
now = time(NULL);
|
||||
|
||||
/* count loaded modules */
|
||||
while (ptr)
|
||||
{
|
||||
ptr = ptr->next;
|
||||
n_mod++;
|
||||
}
|
||||
|
||||
/* module lists pointer is set back to the head */
|
||||
ptr = modules;
|
||||
|
||||
/**
|
||||
* allocate gwbuf for data to send
|
||||
*
|
||||
* each module gives 4 rows
|
||||
* product and release rows add 7 rows
|
||||
* row is _NOTIFICATION_REPORT_ROW_LEN bytes long
|
||||
*/
|
||||
|
||||
report_max_bytes = ((n_mod * 4) + 7) * (_NOTIFICATION_REPORT_ROW_LEN + 1);
|
||||
*buffer = gwbuf_alloc(report_max_bytes);
|
||||
|
||||
if (buffer == NULL) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* encode MAC-sha1 to HEX */
|
||||
gw_bin2hex(hex_setup_info, cfg->mac_sha1, SHA_DIGEST_LENGTH);
|
||||
|
||||
|
||||
data_ptr = (char *)GWBUF_DATA(*buffer);
|
||||
|
||||
snprintf(data_ptr, _NOTIFICATION_REPORT_ROW_LEN, "FEEDBACK_SERVER_UID\t%s\n", hex_setup_info);
|
||||
data_ptr+=strlen(data_ptr);
|
||||
snprintf(data_ptr, _NOTIFICATION_REPORT_ROW_LEN, "FEEDBACK_USER_INFO\t%s\n", cfg->feedback_user_info == NULL ? "not_set" : cfg->feedback_user_info);
|
||||
data_ptr+=strlen(data_ptr);
|
||||
snprintf(data_ptr, _NOTIFICATION_REPORT_ROW_LEN, "VERSION\t%s\n", MAXSCALE_VERSION);
|
||||
data_ptr+=strlen(data_ptr);
|
||||
snprintf(data_ptr, _NOTIFICATION_REPORT_ROW_LEN * 2, "NOW\t%lu\nPRODUCT\t%s\n", now, "maxscale");
|
||||
data_ptr+=strlen(data_ptr);
|
||||
snprintf(data_ptr, _NOTIFICATION_REPORT_ROW_LEN, "Uname_sysname\t%s\n", cfg->sysname);
|
||||
data_ptr+=strlen(data_ptr);
|
||||
snprintf(data_ptr, _NOTIFICATION_REPORT_ROW_LEN, "Uname_distribution\t%s\n", cfg->release_info);
|
||||
data_ptr+=strlen(data_ptr);
|
||||
|
||||
while (ptr)
|
||||
{
|
||||
snprintf(data_ptr, _NOTIFICATION_REPORT_ROW_LEN * 2, "module_%s_type\t%s\nmodule_%s_version\t%s\n", ptr->module, ptr->type, ptr->module, ptr->version);
|
||||
data_ptr+=strlen(data_ptr);
|
||||
|
||||
if (ptr->info) {
|
||||
snprintf(data_ptr, _NOTIFICATION_REPORT_ROW_LEN, "module_%s_api\t%d.%d.%d\n",
|
||||
ptr->module,
|
||||
ptr->info->api_version.major,
|
||||
ptr->info->api_version.minor,
|
||||
ptr->info->api_version.patch);
|
||||
|
||||
data_ptr+=strlen(data_ptr);
|
||||
snprintf(data_ptr, _NOTIFICATION_REPORT_ROW_LEN, "module_%s_releasestatus\t%s\n",
|
||||
ptr->module,
|
||||
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"
|
||||
: (ptr->info->status == MODULE_EXPERIMENTAL
|
||||
? "Experimental" : "Unknown")))));
|
||||
data_ptr+=strlen(data_ptr);
|
||||
}
|
||||
ptr = ptr->next;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
@ -35,6 +35,7 @@
|
||||
* 13/10/14 Massimiliano Pinto Added hashtable for resources (i.e database names for MySQL services)
|
||||
* 06/02/15 Mark Riddoch Added caching of authentication data
|
||||
* 18/02/15 Mark Riddoch Added result set management
|
||||
* 03/03/15 Massimiliano Pinto Added config_enable_feedback_task() call in serviceStartAll
|
||||
*
|
||||
* @endverbatim
|
||||
*/
|
||||
@ -61,7 +62,6 @@
|
||||
#include <housekeeper.h>
|
||||
#include <resultset.h>
|
||||
|
||||
|
||||
/** Defined in log_manager.cc */
|
||||
extern int lm_enabled_logfiles_bitmask;
|
||||
extern size_t log_ses_count[];
|
||||
@ -477,6 +477,8 @@ serviceStartAll()
|
||||
SERVICE *ptr;
|
||||
int n = 0,i;
|
||||
|
||||
config_enable_feedback_task();
|
||||
|
||||
ptr = allServices;
|
||||
while (ptr && !ptr->svc_do_shutdown)
|
||||
{
|
||||
|
@ -12,6 +12,7 @@ add_executable(test_server testserver.c)
|
||||
add_executable(test_users testusers.c)
|
||||
add_executable(test_adminusers testadminusers.c)
|
||||
add_executable(testmemlog testmemlog.c)
|
||||
add_executable(testfeedback testfeedback.c)
|
||||
target_link_libraries(test_mysql_users MySQLClient fullcore)
|
||||
target_link_libraries(test_hash fullcore)
|
||||
target_link_libraries(test_hint fullcore)
|
||||
@ -26,6 +27,7 @@ target_link_libraries(test_server fullcore)
|
||||
target_link_libraries(test_users fullcore)
|
||||
target_link_libraries(test_adminusers fullcore)
|
||||
target_link_libraries(testmemlog fullcore)
|
||||
target_link_libraries(testfeedback fullcore)
|
||||
add_test(testMySQLUsers test_mysql_users)
|
||||
add_test(TestHash test_hash)
|
||||
add_test(TestHint test_hint)
|
||||
@ -40,6 +42,7 @@ add_test(TestServer test_server)
|
||||
add_test(TestUsers test_users)
|
||||
add_test(TestAdminUsers test_adminusers)
|
||||
add_test(TestMemlog testmemlog)
|
||||
add_test(TestFeedback testfeedback)
|
||||
set_tests_properties(testMySQLUsers
|
||||
TestHash
|
||||
TestHint
|
||||
@ -53,4 +56,5 @@ set_tests_properties(testMySQLUsers
|
||||
TestServer
|
||||
TestUsers
|
||||
TestAdminUsers
|
||||
TestMemlog PROPERTIES ENVIRONMENT MAXSCALE_HOME=${CMAKE_BINARY_DIR}/)
|
||||
TestMemlog
|
||||
TestFeedback PROPERTIES ENVIRONMENT MAXSCALE_HOME=${CMAKE_BINARY_DIR}/)
|
||||
|
84
server/core/test/testfeedback.c
Normal file
84
server/core/test/testfeedback.c
Normal file
@ -0,0 +1,84 @@
|
||||
/*
|
||||
* 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 MariaDB Corporation Ab 2014
|
||||
*/
|
||||
|
||||
/**
|
||||
*
|
||||
* @verbatim
|
||||
* Revision History
|
||||
*
|
||||
* Date Who Description
|
||||
* 09-03-2015 Markus Mäkelä Initial implementation
|
||||
*
|
||||
* @endverbatim
|
||||
*/
|
||||
|
||||
#define FAILTEST(s) printf("TEST FAILED: " s "\n");return 1;
|
||||
|
||||
#include <stdio.h>
|
||||
#include <notification.h>
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <housekeeper.h>
|
||||
#include <buffer.h>
|
||||
#include <regex.h>
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
FEEDBACK_CONF* fc;
|
||||
char* home;
|
||||
char* cnf;
|
||||
GWBUF* buf;
|
||||
regex_t re;
|
||||
|
||||
hkinit();
|
||||
home = getenv("MAXSCALE_HOME");
|
||||
|
||||
if(home == NULL)
|
||||
{
|
||||
FAILTEST("MAXSCALE_HOME was not defined.");
|
||||
}
|
||||
printf("Home: %s\n",home);
|
||||
|
||||
cnf = malloc(strlen(home) + strlen("/etc/MaxScale.cnf") + 1);
|
||||
strcpy(cnf,home);
|
||||
strcat(cnf,"/etc/MaxScale.cnf");
|
||||
|
||||
printf("Config: %s\n",cnf);
|
||||
|
||||
config_load(cnf);
|
||||
|
||||
if((fc = config_get_feedback_data()) == NULL ||
|
||||
fc->feedback_user_info == NULL)
|
||||
{
|
||||
FAILTEST("Configuration was NULL.");
|
||||
}
|
||||
|
||||
regcomp(&re,fc->feedback_user_info,0);
|
||||
|
||||
module_create_feedback_report(&buf,NULL,fc);
|
||||
printf("%s",(char*)buf->start);
|
||||
|
||||
if(regexec(&re,(char*)buf->start,0,NULL,0))
|
||||
{
|
||||
FAILTEST("Regex match of 'user_info' failed.");
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
@ -18,7 +18,7 @@
|
||||
* Copyright MariaDB Corporation Ab 2013-2014
|
||||
*/
|
||||
#include <skygw_utils.h>
|
||||
|
||||
#include <openssl/sha.h>
|
||||
/**
|
||||
* @file config.h The configuration handling elements
|
||||
*
|
||||
@ -30,12 +30,15 @@
|
||||
* 07/05/14 Massimiliano Pinto Added version_string to global configuration
|
||||
* 23/05/14 Massimiliano Pinto Added id to global configuration
|
||||
* 17/10/14 Mark Riddoch Added poll tuning configuration parameters
|
||||
* 05/03/15 Massimiliano Pinto Added sysname, release, sha1_mac to gateway struct
|
||||
*
|
||||
* @endverbatim
|
||||
*/
|
||||
|
||||
#define DEFAULT_NBPOLLS 3 /**< Default number of non block polls before we block */
|
||||
#define DEFAULT_POLLSLEEP 1000 /**< Default poll wait time (milliseconds) */
|
||||
#define _SYSNAME_STR_LENGTH 256 /**< sysname len */
|
||||
#define _RELEASE_STR_LENGTH 256 /**< release len */
|
||||
/**
|
||||
* Maximum length for configuration parameter value.
|
||||
*/
|
||||
@ -92,22 +95,25 @@ typedef struct config_context {
|
||||
* The gateway global configuration data
|
||||
*/
|
||||
typedef struct {
|
||||
int n_threads; /**< Number of polling threads */
|
||||
char *version_string; /**< The version string of embedded database library */
|
||||
unsigned long id; /**< MaxScale ID */
|
||||
int n_threads; /**< Number of polling threads */
|
||||
char *version_string; /**< The version string of embedded database library */
|
||||
char release_string[_SYSNAME_STR_LENGTH]; /**< The release name string of the system */
|
||||
char sysname[_SYSNAME_STR_LENGTH]; /**< The release name string of the system */
|
||||
uint8_t mac_sha1[SHA_DIGEST_LENGTH]; /*< The SHA1 digest of an interface MAC address */
|
||||
unsigned long id; /**< MaxScale ID */
|
||||
unsigned int n_nbpoll; /**< Tune number of non-blocking polls */
|
||||
unsigned int pollsleep; /**< Wait time in blocking polls */
|
||||
} GATEWAY_CONF;
|
||||
|
||||
extern int config_load(char *);
|
||||
extern int config_reload();
|
||||
extern int config_threadcount();
|
||||
extern unsigned int config_nbpolls();
|
||||
extern unsigned int config_pollsleep();
|
||||
CONFIG_PARAMETER* config_get_param(CONFIG_PARAMETER* params, const char* name);
|
||||
config_param_type_t config_get_paramtype(CONFIG_PARAMETER* param);
|
||||
CONFIG_PARAMETER* config_clone_param(CONFIG_PARAMETER* param);
|
||||
int config_truth_value(char *str);
|
||||
extern int config_load(char *);
|
||||
extern int config_reload();
|
||||
extern int config_threadcount();
|
||||
extern unsigned int config_nbpolls();
|
||||
extern unsigned int config_pollsleep();
|
||||
CONFIG_PARAMETER* config_get_param(CONFIG_PARAMETER* params, const char* name);
|
||||
config_param_type_t config_get_paramtype(CONFIG_PARAMETER* param);
|
||||
CONFIG_PARAMETER* config_clone_param(CONFIG_PARAMETER* param);
|
||||
extern int config_truth_value(char *);
|
||||
bool config_set_qualified_param(
|
||||
CONFIG_PARAMETER* param,
|
||||
void* val,
|
||||
@ -131,4 +137,7 @@ bool config_get_valtarget(
|
||||
CONFIG_PARAMETER* param,
|
||||
const char* name, /*< if NULL examine current param only */
|
||||
config_param_type_t ptype);
|
||||
|
||||
void config_enable_feedback_task(void);
|
||||
void config_disable_feedback_task(void);
|
||||
#endif
|
||||
|
@ -29,13 +29,15 @@
|
||||
* @verbatim
|
||||
* Revision History
|
||||
*
|
||||
* Date Who Description
|
||||
* 13/06/13 Mark Riddoch Initial implementation
|
||||
* 08/07/13 Mark Riddoch Addition of monitor modules
|
||||
* 29/05/14 Mark Riddoch Addition of filter modules
|
||||
* 01/10/14 Mark Riddoch Addition of call to unload all modules on
|
||||
* shutdown
|
||||
* 19/02/15 Mark Riddoch Addition of moduleGetList
|
||||
* Date Who Description
|
||||
* 13/06/13 Mark Riddoch Initial implementation
|
||||
* 08/07/13 Mark Riddoch Addition of monitor modules
|
||||
* 29/05/14 Mark Riddoch Addition of filter modules
|
||||
* 01/10/14 Mark Riddoch Addition of call to unload all modules on
|
||||
* shutdown
|
||||
* 19/02/15 Mark Riddoch Addition of moduleGetList
|
||||
* 26/02/15 Massimiliano Pinto Addition of module_feedback_send
|
||||
*
|
||||
* @endverbatim
|
||||
*/
|
||||
|
||||
@ -65,7 +67,9 @@ extern void unload_module(const char *module);
|
||||
extern void unload_all_modules();
|
||||
extern void printModules();
|
||||
extern void dprintAllModules(DCB *);
|
||||
extern char *get_maxscale_home(void);
|
||||
extern RESULTSET *moduleGetList();
|
||||
extern char *get_maxscale_home(void);
|
||||
extern void module_feedback_send(void*);
|
||||
extern void moduleShowFeedbackReport(DCB *dcb);
|
||||
|
||||
#endif
|
||||
|
63
server/include/notification.h
Normal file
63
server/include/notification.h
Normal file
@ -0,0 +1,63 @@
|
||||
#ifndef _NOTIFICATION_SERVICE_H
|
||||
#define _NOTIFICATION_SERVICE_H
|
||||
/*
|
||||
* This file is distributed as part of the MariaDB Corporation 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 MariaDB Corporation Ab 2013-2014
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file notification.h
|
||||
*
|
||||
* The configuration stuct for notification/feedback service
|
||||
*
|
||||
* @verbatim
|
||||
* Revision History
|
||||
*
|
||||
* Date Who Description
|
||||
* 02/03/15 Massimiliano Pinto Initial implementation
|
||||
*
|
||||
* @endverbatim
|
||||
*/
|
||||
|
||||
#define _NOTIFICATION_CONNECT_TIMEOUT 30
|
||||
#define _NOTIFICATION_OPERATION_TIMEOUT 30
|
||||
#define _NOTIFICATION_SEND_PENDING 0
|
||||
#define _NOTIFICATION_SEND_OK 1
|
||||
#define _NOTIFICATION_SEND_ERROR 2
|
||||
#define _NOTIFICATION_REPORT_ROW_LEN 255
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
/**
|
||||
* The configuration and usage information data for feeback service
|
||||
*/
|
||||
|
||||
typedef struct {
|
||||
int feedback_enable; /**< Enable/Disable Notification feedback */
|
||||
char *feedback_url; /**< URL to which the data is sent */
|
||||
char *feedback_user_info; /**< User info included in the feedback data sent */
|
||||
int feedback_timeout; /**< An attempt to write/read the data times out and fails after this many seconds */
|
||||
int feedback_connect_timeout; /**< An attempt to send the data times out and fails after this many seconds */
|
||||
int feedback_last_action; /**< Holds the feedback last send action status */
|
||||
char *release_info; /**< Operating system Release name */
|
||||
char *sysname; /**< Operating system name */
|
||||
uint8_t *mac_sha1; /**< First available MAC address*/
|
||||
} FEEDBACK_CONF;
|
||||
|
||||
extern char *gw_bin2hex(char *out, const uint8_t *in, unsigned int len);
|
||||
extern void gw_sha1_str(const uint8_t *in, int in_len, uint8_t *out);
|
||||
extern FEEDBACK_CONF * config_get_feedback_data();
|
||||
#endif
|
@ -36,12 +36,13 @@
|
||||
* Date Who Description
|
||||
* 20/06/13 Mark Riddoch Initial implementation
|
||||
* 17/07/13 Mark Riddoch Additional commands
|
||||
* 09/08/2013 Massimiliano Pinto Added enable/disable commands (now only for log)
|
||||
* 09/08/13 Massimiliano Pinto Added enable/disable commands (now only for log)
|
||||
* 20/05/14 Mark Riddoch Added ability to give server and service names rather
|
||||
* than simply addresses
|
||||
* 23/05/14 Mark Riddoch Added support for developer and user modes
|
||||
* 29/05/14 Mark Riddoch Add Filter support
|
||||
* 16/10/14 Mark Riddoch Add show eventq
|
||||
* 05/03/15 Massimiliano Pinto Added enable/disable feedback
|
||||
*
|
||||
* @endverbatim
|
||||
*/
|
||||
@ -129,6 +130,10 @@ struct subcommand showoptions[] = {
|
||||
"Show the event statistics",
|
||||
"Show the event statistics",
|
||||
{0, 0, 0} },
|
||||
{ "feedbackreport", 0, moduleShowFeedbackReport,
|
||||
"Show the report of MaxScale loaded modules, suitable for Notification Service",
|
||||
"Show the report of MaxScale loaded modules, suitable for Notification Service",
|
||||
{0, 0, 0} },
|
||||
{ "filter", 1, dprintFilter,
|
||||
"Show details of a filter, called with a filter name",
|
||||
"Show details of a filter, called with the address of a filter",
|
||||
@ -365,6 +370,8 @@ static void enable_monitor_replication_heartbeat(DCB *dcb, MONITOR *monitor);
|
||||
static void disable_monitor_replication_heartbeat(DCB *dcb, MONITOR *monitor);
|
||||
static void enable_service_root(DCB *dcb, SERVICE *service);
|
||||
static void disable_service_root(DCB *dcb, SERVICE *service);
|
||||
static void enable_feedback_action();
|
||||
static void disable_feedback_action();
|
||||
|
||||
/**
|
||||
* * The subcommands of the enable command
|
||||
@ -406,6 +413,14 @@ struct subcommand enableoptions[] = {
|
||||
"Enable root access to a service, pass a service name to enable root access",
|
||||
{ARG_TYPE_SERVICE, 0, 0}
|
||||
},
|
||||
{
|
||||
"feedback",
|
||||
0,
|
||||
enable_feedback_action,
|
||||
"Enable MaxScale modules list sending via http to notification service",
|
||||
"Enable MaxScale modules list sending via http to notification service",
|
||||
{0, 0, 0}
|
||||
},
|
||||
{
|
||||
NULL,
|
||||
0,
|
||||
@ -458,6 +473,14 @@ struct subcommand disableoptions[] = {
|
||||
"Disable root access to a service",
|
||||
{ARG_TYPE_SERVICE, 0, 0}
|
||||
},
|
||||
{
|
||||
"feedback",
|
||||
0,
|
||||
disable_feedback_action,
|
||||
"Disable MaxScale modules list sending via http to notification service",
|
||||
"Disable MaxScale modules list sending via http to notification service",
|
||||
{0, 0, 0}
|
||||
},
|
||||
{
|
||||
NULL,
|
||||
0,
|
||||
@ -1381,6 +1404,29 @@ set_nbpoll(DCB *dcb, int nb)
|
||||
poll_set_nonblocking_polls(nb);
|
||||
}
|
||||
|
||||
/**
|
||||
* Re-enable sendig MaxScale module list via http
|
||||
* Proper [feedback] section in MaxSclale.cnf
|
||||
* is required.
|
||||
*/
|
||||
static void
|
||||
enable_feedback_action(void)
|
||||
{
|
||||
config_enable_feedback_task();
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Disable sendig MaxScale module list via http
|
||||
*/
|
||||
|
||||
static void
|
||||
disable_feedback_action(void)
|
||||
{
|
||||
config_disable_feedback_task();
|
||||
return;
|
||||
}
|
||||
|
||||
#if defined(FAKE_CODE)
|
||||
static void fail_backendfd(void)
|
||||
{
|
||||
|
@ -1,6 +1,13 @@
|
||||
[maxscale]
|
||||
threads=4
|
||||
|
||||
[feedback]
|
||||
feedback_enable=true
|
||||
feedback_user_info=user_info
|
||||
feedback_url=http://127.0.0.1:8080/load.php
|
||||
feedback_timeout=60
|
||||
feedback_connect_timeout=60
|
||||
|
||||
[MySQL Monitor]
|
||||
type=monitor
|
||||
module=mysqlmon
|
||||
|
Loading…
x
Reference in New Issue
Block a user