Merge branch 'develop' into MXS-329-develop-20151111
This commit is contained in:
commit
6b88b6b17f
@ -81,22 +81,6 @@ This disables the assignment of master and slave roles to the Galera cluster nod
|
||||
```
|
||||
disable_master_role_setting=true
|
||||
```
|
||||
|
||||
### `script`
|
||||
|
||||
This script will be executed when a server changes its state. The parameter should be an absolute path to the script or it should be in the executable path. The user which is used to run MaxScale should have execution rights to the file itself and the directory it resides in.
|
||||
|
||||
```
|
||||
script=/home/user/script.sh
|
||||
```
|
||||
|
||||
### `events`
|
||||
|
||||
A list of event names which cause the script to be executed. If this option is not defined, all events cause the script to be executed. The list must contain a comma separated list of event names.
|
||||
|
||||
```
|
||||
events=master_down,slave_down
|
||||
```
|
||||
|
||||
### `use_priority`
|
||||
|
||||
@ -106,6 +90,10 @@ Enable interaction with server priorities. This will allow the monitor to determ
|
||||
use_priority=true
|
||||
```
|
||||
|
||||
### Common Monitor Parameters
|
||||
|
||||
For a list of optional parameters that all monitors support, read the [Monitor Common](Monitor-Common.md) document.
|
||||
|
||||
## Interaction with Server Priorities
|
||||
|
||||
If the `use_priority` option is set and a server is configured with the `priority=<int>` parameter, galeramon will use that as the basis on which the master node is chosen. This requires the `disable_master_role_setting` to be undefined or disabled. The server with the lowest value in `priority` will be chosen as the master node when a replacement Galera node is promoted to a master server inside MaxScale.
|
||||
@ -135,24 +123,3 @@ priority=2
|
||||
In this example `node-1` is always used as the master if available. If `node-1` is not available, then the next node with the highest priority rank is used. In this case it would be `node-3`. If both `node-1` and `node-3` were down, then `node-2` would be used. Nodes without priority are considered as having the lowest priority rank and will be used only if all nodes with priority ranks are not available.
|
||||
|
||||
With priority ranks you can control the order in which MaxScale chooses the master node. This will allow for a controlled failure and replacement of nodes.
|
||||
|
||||
## Script events
|
||||
|
||||
Here is a table of all possible event types and their descriptions.
|
||||
|
||||
Event Name|Description
|
||||
----------|----------
|
||||
master_down|A Master server has gone down
|
||||
master_up|A Master server has come up
|
||||
slave_down|A Slave server has gone down
|
||||
slave_up|A Slave server has come up
|
||||
server_down|A server with no assigned role has gone down
|
||||
server_up|A server with no assigned role has come up
|
||||
synced_down|A synced Galera node has come up
|
||||
synced_up|A synced Galera node has gone down
|
||||
lost_master|A server lost Master status
|
||||
lost_slave|A server lost Slave status
|
||||
lost_synced|A Galera node lost synced status
|
||||
new_master|A new Master was detected
|
||||
new_slave|A new Slave was detected
|
||||
new_synced|A new synced Galera node was detected
|
||||
|
@ -67,41 +67,7 @@ This is a situation which can happen if all slave servers are unreachable or the
|
||||
```
|
||||
detect_stale_master=true
|
||||
```
|
||||
|
||||
### `script`
|
||||
|
||||
This script will be executed when a server changes its state. The parameter should be an absolute path to the script or it should be in the executable path. The user which is used to run MaxScale should have execution rights to the file itself and the directory it resides in.
|
||||
### Common Monitor Parameters
|
||||
|
||||
```
|
||||
script=/home/user/script.sh
|
||||
```
|
||||
|
||||
This script will be called with the following command line arguments.
|
||||
|
||||
```
|
||||
<name of the script> --event=<event type> --initiator=<server whose state changed> --nodelist=<list of all servers>
|
||||
```
|
||||
### `events`
|
||||
|
||||
A list of event names which cause the script to be executed. If this option is not defined, all events cause the script to be executed. The list must contain a comma separated list of event names.
|
||||
|
||||
```
|
||||
events=master_down,slave_down
|
||||
```
|
||||
|
||||
## Script events
|
||||
|
||||
Here is a table of all possible event types and their descriptions.
|
||||
|
||||
Event Name|Description
|
||||
----------|----------
|
||||
master_down|A Master server has gone down
|
||||
master_up|A Master server has come up
|
||||
slave_down|A Slave server has gone down
|
||||
slave_up|A Slave server has come up
|
||||
server_down|A server with no assigned role has gone down
|
||||
server_up|A server with no assigned role has come up
|
||||
lost_master|A server lost Master status
|
||||
lost_slave|A server lost Slave status
|
||||
new_master|A new Master was detected
|
||||
new_slave|A new Slave was detected
|
||||
For a list of optional parameters that all monitors support, read the [Monitor Common](Monitor-Common.md) document.
|
||||
|
55
Documentation/Monitors/Monitor-Common.md
Normal file
55
Documentation/Monitors/Monitor-Common.md
Normal file
@ -0,0 +1,55 @@
|
||||
# Common Monitor Parameters
|
||||
|
||||
This document lists optional parameters that all current monitors support.
|
||||
|
||||
## Parameters
|
||||
|
||||
### `script`
|
||||
|
||||
This command will be executed when a server changes its state. The parameter should be an absolute path to a command or the command should be in the executable path. The user which is used to run MaxScale should have execution rights to the file itself and the directory it resides in.
|
||||
|
||||
```
|
||||
script=/home/user/myscript.sh initiator=$INITIATOR event=$EVENT live_nodes=$NODELIST
|
||||
```
|
||||
|
||||
The following substitutions will be made to the parameter value:
|
||||
|
||||
* `$INITIATOR` will be replaced with the IP and port of the server who initiated the event
|
||||
* `$EVENT` will be replaced with the name of the event
|
||||
* `$NODELIST` will be replaced with a list of server IPs and ports that are running
|
||||
|
||||
For example, the previous example will be executed as:
|
||||
|
||||
```
|
||||
/home/user/myscript.sh initiator=192.168.0.10:3306 event=master_down live_nodes=192.168.0.201:3306,192.168.0.121:3306
|
||||
```
|
||||
|
||||
### `events`
|
||||
|
||||
A list of event names which cause the script to be executed. If this option is not defined, all events cause the script to be executed. The list must contain a comma separated list of event names.
|
||||
|
||||
```
|
||||
events=master_down,slave_down
|
||||
```
|
||||
|
||||
## Script events
|
||||
|
||||
Here is a table of all possible event types and their descriptions that the monitors can be called with.
|
||||
|
||||
Event Name|Description
|
||||
----------|----------
|
||||
master_down|A Master server has gone down
|
||||
master_up|A Master server has come up
|
||||
slave_down|A Slave server has gone down
|
||||
slave_up|A Slave server has come up
|
||||
server_down|A server with no assigned role has gone down
|
||||
server_up|A server with no assigned role has come up
|
||||
ndb_down|A MySQL Cluster node has gone down
|
||||
ndb_up|A MySQL Cluster node has come up
|
||||
lost_master|A server lost Master status
|
||||
lost_slave|A server lost Slave status
|
||||
lost_ndb|A MySQL Cluster node lost node membership
|
||||
new_master|A new Master was detected
|
||||
new_slave|A new Slave was detected
|
||||
new_ndb|A new MySQL Cluster node was found
|
||||
|
@ -83,27 +83,6 @@ This is a situation which can happen if all slave servers are unreachable or the
|
||||
```
|
||||
detect_stale_master=true
|
||||
```
|
||||
|
||||
### `script`
|
||||
|
||||
This script will be executed when a server changes its state. The parameter should be an absolute path to the script or it should be in the executable path. The user which is used to run MaxScale should have execution rights to the file itself and the directory it resides in.
|
||||
|
||||
```
|
||||
script=/home/user/script.sh
|
||||
```
|
||||
|
||||
This script will be called with the following command line arguments.
|
||||
|
||||
```
|
||||
<name of the script> --event=<event type> --initiator=<server whose state changed> --nodelist=<list of all servers>
|
||||
```
|
||||
### `events`
|
||||
|
||||
A list of event names which cause the script to be executed. If this option is not defined, all events cause the script to be executed. The list must contain a comma separated list of event names.
|
||||
|
||||
```
|
||||
events=master_down,slave_down
|
||||
```
|
||||
|
||||
### `mysql51_replication`
|
||||
|
||||
@ -113,23 +92,9 @@ Enable support for MySQL 5.1 replication monitoring. This is needed if a MySQL s
|
||||
mysql51_replication=true
|
||||
```
|
||||
|
||||
## Script events
|
||||
|
||||
Here is a table of all possible event types and their descriptions.
|
||||
|
||||
Event Name|Description
|
||||
----------|----------
|
||||
master_down|A Master server has gone down
|
||||
master_up|A Master server has come up
|
||||
slave_down|A Slave server has gone down
|
||||
slave_up|A Slave server has come up
|
||||
server_down|A server with no assigned role has gone down
|
||||
server_up|A server with no assigned role has come up
|
||||
lost_master|A server lost Master status
|
||||
lost_slave|A server lost Slave status
|
||||
new_master|A new Master was detected
|
||||
new_slave|A new Slave was detected
|
||||
### Common Monitor Parameters
|
||||
|
||||
For a list of optional parameters that all monitors support, read the [Monitor Common](Monitor-Common.md) document.
|
||||
|
||||
## Example 1 - Monitor script
|
||||
|
||||
|
@ -54,49 +54,6 @@ This parameter controls the timeout for reading from a monitored server. It is i
|
||||
backend_read_timeout=2
|
||||
```
|
||||
|
||||
## MySQL Cluster Monitor optional parameters
|
||||
|
||||
These are optional parameters specific to the MySQL Cluster Monitor.
|
||||
|
||||
### `script`
|
||||
|
||||
This script will be executed when a server changes its state. The parameter should be an absolute path to the script or it should be in the executable path. The user which is used to run MaxScale should have execution rights to the file itself and the directory it resides in.
|
||||
|
||||
```
|
||||
script=/home/user/script.sh
|
||||
```
|
||||
|
||||
This script will be called with the following command line arguments.
|
||||
|
||||
```
|
||||
<name of the script> --event=<event type> --initiator=<server whose state changed> --nodelist=<list of all servers>
|
||||
```
|
||||
### `events`
|
||||
|
||||
A list of event names which cause the script to be executed. If this option is not defined, all events cause the script to be executed. The list must contain a comma separated list of event names.
|
||||
|
||||
```
|
||||
events=master_down,slave_down
|
||||
```
|
||||
|
||||
## Script events
|
||||
|
||||
Here is a table of all possible event types and their descriptions that the MySQL Cluster monitor can be called with.
|
||||
|
||||
Event Name|Description
|
||||
----------|----------
|
||||
master_down|A Master server has gone down
|
||||
master_up|A Master server has come up
|
||||
slave_down|A Slave server has gone down
|
||||
slave_up|A Slave server has come up
|
||||
server_down|A server with no assigned role has gone down
|
||||
server_up|A server with no assigned role has come up
|
||||
ndb_down|A MySQL Cluster node has gone down
|
||||
ndb_up|A MySQL Cluster node has come up
|
||||
lost_master|A server lost Master status
|
||||
lost_slave|A server lost Slave status
|
||||
lost_ndb|A MySQL Cluster node lost node membership
|
||||
new_master|A new Master was detected
|
||||
new_slave|A new Slave was detected
|
||||
new_ndb|A new MySQL Cluster node was found
|
||||
### Common Monitor Parameters
|
||||
|
||||
For a list of optional parameters that all monitors support, read the [Monitor Common](Monitor-Common.md) document.
|
||||
|
@ -67,6 +67,8 @@ Uptime: 72 Threads: 1 Sessions: 11
|
||||
|
||||
The SQL command used to interact with maxinfo is the show command, a variety of show commands are available and will be described in the following sections.
|
||||
|
||||
Maxinfo also supports the `FLUSH LOGS`, `SET SERVER <name> <status>` and `CLEAR SERVER <name> <status>` commands. These behave the same as their MaxAdmin counterpart.
|
||||
|
||||
## Show variables
|
||||
|
||||
The show variables command will display a set of name and value pairs for a number of MaxScale system variables.
|
||||
|
@ -81,10 +81,10 @@ start() {
|
||||
mkdir -p @MAXSCALE_VARDIR@/run/maxscale
|
||||
fi
|
||||
|
||||
chown maxscale:maxscale @MAXSCALE_VARDIR@/log/maxscale
|
||||
chown maxscale:maxscale @MAXSCALE_VARDIR@/lib/maxscale
|
||||
chown maxscale:maxscale @MAXSCALE_VARDIR@/cache/maxscale
|
||||
chown maxscale:maxscale @MAXSCALE_VARDIR@/run/maxscale
|
||||
chown -R maxscale:maxscale @MAXSCALE_VARDIR@/log/maxscale
|
||||
chown -R maxscale:maxscale @MAXSCALE_VARDIR@/lib/maxscale
|
||||
chown -R maxscale:maxscale @MAXSCALE_VARDIR@/cache/maxscale
|
||||
chown -R maxscale:maxscale @MAXSCALE_VARDIR@/run/maxscale
|
||||
chmod 0755 @MAXSCALE_VARDIR@/log/maxscale
|
||||
chmod 0755 @MAXSCALE_VARDIR@/lib/maxscale
|
||||
chmod 0755 @MAXSCALE_VARDIR@/cache/maxscale
|
||||
|
@ -21,10 +21,10 @@ then
|
||||
fi
|
||||
|
||||
# Change the owner of the directories to maxscale:maxscale
|
||||
chown maxscale:maxscale @MAXSCALE_VARDIR@/log/maxscale
|
||||
chown maxscale:maxscale @MAXSCALE_VARDIR@/lib/maxscale
|
||||
chown maxscale:maxscale @MAXSCALE_VARDIR@/cache/maxscale
|
||||
chown maxscale:maxscale @MAXSCALE_VARDIR@/run/maxscale
|
||||
chown -R maxscale:maxscale @MAXSCALE_VARDIR@/log/maxscale
|
||||
chown -R maxscale:maxscale @MAXSCALE_VARDIR@/lib/maxscale
|
||||
chown -R maxscale:maxscale @MAXSCALE_VARDIR@/cache/maxscale
|
||||
chown -R maxscale:maxscale @MAXSCALE_VARDIR@/run/maxscale
|
||||
chmod 0755 @MAXSCALE_VARDIR@/log/maxscale
|
||||
chmod 0755 @MAXSCALE_VARDIR@/lib/maxscale
|
||||
chmod 0755 @MAXSCALE_VARDIR@/cache/maxscale
|
||||
|
@ -81,10 +81,10 @@ start() {
|
||||
mkdir -p @MAXSCALE_VARDIR@/run/maxscale
|
||||
fi
|
||||
|
||||
chown maxscale:maxscale @MAXSCALE_VARDIR@/log/maxscale
|
||||
chown maxscale:maxscale @MAXSCALE_VARDIR@/lib/maxscale
|
||||
chown maxscale:maxscale @MAXSCALE_VARDIR@/cache/maxscale
|
||||
chown maxscale:maxscale @MAXSCALE_VARDIR@/run/maxscale
|
||||
chown -R maxscale:maxscale @MAXSCALE_VARDIR@/log/maxscale
|
||||
chown -R maxscale:maxscale @MAXSCALE_VARDIR@/lib/maxscale
|
||||
chown -R maxscale:maxscale @MAXSCALE_VARDIR@/cache/maxscale
|
||||
chown -R maxscale:maxscale @MAXSCALE_VARDIR@/run/maxscale
|
||||
chmod 0755 @MAXSCALE_VARDIR@/log/maxscale
|
||||
chmod 0755 @MAXSCALE_VARDIR@/lib/maxscale
|
||||
chmod 0755 @MAXSCALE_VARDIR@/cache/maxscale
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -18,6 +18,8 @@
|
||||
#if !defined(LOG_MANAGER_H)
|
||||
# define LOG_MANAGER_H
|
||||
|
||||
#include <syslog.h>
|
||||
|
||||
/*
|
||||
* We need a common.h file that is included by every component.
|
||||
*/
|
||||
@ -42,7 +44,6 @@ typedef enum
|
||||
LOGFILE_LAST = LOGFILE_DEBUG
|
||||
} logfile_id_t;
|
||||
|
||||
|
||||
typedef enum
|
||||
{
|
||||
FILEWRITER_INIT,
|
||||
@ -50,6 +51,13 @@ typedef enum
|
||||
FILEWRITER_DONE
|
||||
} filewriter_state_t;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
LOG_TARGET_DEFAULT = 0,
|
||||
LOG_TARGET_FS = 1, // File system
|
||||
LOG_TARGET_SHMEM = 2, // Shared memory
|
||||
} log_target_t;
|
||||
|
||||
/**
|
||||
* Thread-specific logging information.
|
||||
*/
|
||||
@ -124,78 +132,53 @@ typedef enum
|
||||
LOG_AUGMENTATION_MASK = (LOG_AUGMENT_WITH_FUNCTION)
|
||||
} log_augmentation_t;
|
||||
|
||||
/**
|
||||
* LOG_FLUSH_NO Do not flush after writing.
|
||||
* LOG_FLUSH_YES Flush after writing.
|
||||
*/
|
||||
enum log_flush
|
||||
{
|
||||
LOG_FLUSH_NO = 0,
|
||||
LOG_FLUSH_YES = 1
|
||||
};
|
||||
|
||||
EXTERN_C_BLOCK_BEGIN
|
||||
|
||||
extern int lm_enabled_logfiles_bitmask;
|
||||
extern ssize_t log_ses_count[];
|
||||
extern __thread log_info_t tls_log_info;
|
||||
|
||||
bool mxs_log_init(const char* ident, const char* logdir, log_target_t target);
|
||||
void mxs_log_finish(void);
|
||||
|
||||
int mxs_log_flush();
|
||||
int mxs_log_flush_sync();
|
||||
int mxs_log_rotate();
|
||||
int mxs_log_enable_priority(int priority);
|
||||
int mxs_log_disable_priority(int priority);
|
||||
|
||||
bool skygw_logmanager_init(const char* logdir, int argc, char* argv[]);
|
||||
void skygw_logmanager_done(void);
|
||||
void skygw_logmanager_exit(void);
|
||||
int mxs_log_set_priority_enabled(int priority, bool enabled);
|
||||
void mxs_log_set_syslog_enabled(bool enabled);
|
||||
void mxs_log_set_maxscalelog_enabled(bool enabled);
|
||||
void mxs_log_set_highprecision_enabled(bool enabled);
|
||||
void mxs_log_set_augmentation(int bits);
|
||||
|
||||
int mxs_log_message(int priority,
|
||||
const char* file, int line, const char* function,
|
||||
const char* format, ...);
|
||||
|
||||
/**
|
||||
* free private write buffer list
|
||||
*/
|
||||
void skygw_log_done(void);
|
||||
int skygw_log_write_context(logfile_id_t id,
|
||||
enum log_flush flush,
|
||||
const char* file, int line, const char* function,
|
||||
const char* format, ...);
|
||||
int skygw_log_flush(logfile_id_t id);
|
||||
void skygw_log_sync_all(void);
|
||||
int skygw_log_rotate(logfile_id_t id);
|
||||
int skygw_log_enable(logfile_id_t id);
|
||||
int skygw_log_disable(logfile_id_t id);
|
||||
void skygw_log_sync_all(void);
|
||||
void skygw_set_highp(int);
|
||||
void logmanager_enable_syslog(int);
|
||||
void logmanager_enable_maxscalelog(int);
|
||||
|
||||
inline int mxs_log_id_to_priority(logfile_id_t id)
|
||||
{
|
||||
if (id & LOGFILE_ERROR) return LOG_ERR;
|
||||
if (id & LOGFILE_MESSAGE) return LOG_NOTICE;
|
||||
if (id & LOGFILE_TRACE) return LOG_INFO;
|
||||
if (id & LOGFILE_DEBUG) return LOG_DEBUG;
|
||||
return LOG_ERR;
|
||||
}
|
||||
|
||||
#define skygw_log_write(id, format, ...)\
|
||||
skygw_log_write_context(id, LOG_FLUSH_NO, __FILE__, __LINE__, __func__, format, ##__VA_ARGS__)
|
||||
mxs_log_message(mxs_log_id_to_priority(id), __FILE__, __LINE__, __func__, format, ##__VA_ARGS__)
|
||||
|
||||
#define skygw_log_write_flush(id, format, ...)\
|
||||
skygw_log_write_context(id, LOG_FLUSH_YES, __FILE__, __LINE__, __func__, format, ##__VA_ARGS__)
|
||||
|
||||
/**
|
||||
* What augmentation if any should a logged message be augmented with.
|
||||
*
|
||||
* Currently this is a global setting and affects all loggers.
|
||||
*/
|
||||
void skygw_log_set_augmentation(int bits);
|
||||
int skygw_log_get_augmentation();
|
||||
#define skygw_log_write_flush(id, format, ...) skygw_log_write(id, format, ##__VA_ARGS__)
|
||||
|
||||
EXTERN_C_BLOCK_END
|
||||
|
||||
const char* get_logpath_default(void);
|
||||
|
||||
/**
|
||||
* Helper, not to be called directly.
|
||||
*/
|
||||
#define MXS_MESSAGE_FLUSH(id, format, ...)\
|
||||
do { if (LOG_IS_ENABLED(id)) { skygw_log_write_flush(id, format, ##__VA_ARGS__); } } while (false)
|
||||
|
||||
/**
|
||||
* Helper, not to be called directly.
|
||||
*/
|
||||
#define MXS_MESSAGE(id, format, ...)\
|
||||
do { if (LOG_IS_ENABLED(id)) { skygw_log_write(id, format, ##__VA_ARGS__); } } while (false)
|
||||
#define MXS_LOG_MESSAGE(priority, format, ...)\
|
||||
mxs_log_message(priority, __FILE__, __LINE__, __func__, format, ##__VA_ARGS__)
|
||||
|
||||
/**
|
||||
* Log an error, warning, notice, info, or debug message.
|
||||
@ -203,10 +186,10 @@ const char* get_logpath_default(void);
|
||||
* @param format The printf format of the message.
|
||||
* @param ... Arguments, depending on the format.
|
||||
*/
|
||||
#define MXS_ERROR(format, ...) MXS_MESSAGE_FLUSH(LOGFILE_ERROR, format, ##__VA_ARGS__)
|
||||
#define MXS_WARNING(format, ...) MXS_MESSAGE(LOGFILE_ERROR, format, ##__VA_ARGS__)
|
||||
#define MXS_NOTICE(format, ...) MXS_MESSAGE(LOGFILE_MESSAGE, format, ##__VA_ARGS__)
|
||||
#define MXS_INFO(format, ...) MXS_MESSAGE(LOGFILE_TRACE, format, ##__VA_ARGS__)
|
||||
#define MXS_DEBUG(format, ...) MXS_MESSAGE(LOGFILE_DEBUG, format, ##__VA_ARGS__)
|
||||
#define MXS_ERROR(format, ...) MXS_LOG_MESSAGE(LOG_ERR, format, ##__VA_ARGS__)
|
||||
#define MXS_WARNING(format, ...) MXS_LOG_MESSAGE(LOG_WARNING, format, ##__VA_ARGS__)
|
||||
#define MXS_NOTICE(format, ...) MXS_LOG_MESSAGE(LOG_NOTICE, format, ##__VA_ARGS__)
|
||||
#define MXS_INFO(format, ...) MXS_LOG_MESSAGE(LOG_INFO, format, ##__VA_ARGS__)
|
||||
#define MXS_DEBUG(format, ...) MXS_LOG_MESSAGE(LOG_DEBUG, format, ##__VA_ARGS__)
|
||||
|
||||
#endif /** LOG_MANAGER_H */
|
||||
|
@ -3,3 +3,4 @@ add_executable(testorder testorder.c ../../server/core/random_jkiss.c)
|
||||
target_link_libraries(testlog pthread log_manager utils fullcore)
|
||||
target_link_libraries(testorder pthread log_manager utils fullcore)
|
||||
add_test(NAME Internal-TestLogOrder COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/logorder.sh 200 0 1000 ${CMAKE_CURRENT_BINARY_DIR}/logorder.log)
|
||||
add_test(Internal-TestLog testlog)
|
||||
|
@ -24,6 +24,7 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <libgen.h>
|
||||
#include <skygw_utils.h>
|
||||
#include <log_manager.h>
|
||||
|
||||
@ -52,6 +53,15 @@ static void* thr_run_morelog(void* data);
|
||||
#define TEST3
|
||||
#define TEST4
|
||||
|
||||
const char USAGE[]=
|
||||
"usage: %s [-t <#threads>]\n"
|
||||
"\n"
|
||||
"-t: Number of threads. Default is %d.\n";
|
||||
const int N_THR = 4;
|
||||
|
||||
#define TEST_ERROR(msg)\
|
||||
do { fprintf(stderr, "[%s:%d]: %s\n", basename(__FILE__), __LINE__, msg); } while (false)
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
int err = 0;
|
||||
@ -66,30 +76,34 @@ int main(int argc, char* argv[])
|
||||
time_t t;
|
||||
struct tm tm;
|
||||
char c;
|
||||
int nthr = 0;
|
||||
int log_argc = 0;
|
||||
char** log_argv = NULL;
|
||||
int nthr = N_THR;
|
||||
|
||||
while ((c = getopt(argc, argv, "t:")) != -1)
|
||||
{
|
||||
switch (c) {
|
||||
case 't':
|
||||
nthr = atoi(optarg);
|
||||
if (nthr <= 0)
|
||||
{
|
||||
err = 1;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
err = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (nthr <= 0)
|
||||
if (err != 0)
|
||||
{
|
||||
fprintf(stderr, "Thread count argument is zero or "
|
||||
"negative. Exiting.\n");
|
||||
fprintf(stderr, USAGE, argv[0], N_THR);
|
||||
err = 1;
|
||||
goto return_err;
|
||||
}
|
||||
|
||||
printf("Using %d threads.\n", nthr);
|
||||
|
||||
thr = (thread_t **)calloc(1, nthr*sizeof(thread_t*));
|
||||
|
||||
if (thr == NULL)
|
||||
@ -99,14 +113,14 @@ int main(int argc, char* argv[])
|
||||
err = 1;
|
||||
goto return_err;
|
||||
}
|
||||
i = atexit(skygw_logmanager_exit);
|
||||
i = atexit(mxs_log_finish);
|
||||
|
||||
if (i != 0)
|
||||
{
|
||||
fprintf(stderr, "Couldn't register exit function.\n");
|
||||
}
|
||||
|
||||
succp = skygw_logmanager_init("/tmp", log_argc, log_argv);
|
||||
succp = mxs_log_init(NULL, "/tmp", LOG_TARGET_FS);
|
||||
|
||||
if (!succp)
|
||||
{
|
||||
@ -125,7 +139,7 @@ int main(int argc, char* argv[])
|
||||
tm.tm_min,
|
||||
tm.tm_sec);
|
||||
|
||||
skygw_logmanager_init("/tmp", log_argc, log_argv);
|
||||
mxs_log_init(NULL, "/tmp", LOG_TARGET_FS);
|
||||
logstr = ("First write with flush.");
|
||||
err = skygw_log_write_flush(LOGFILE_ERROR, logstr);
|
||||
|
||||
@ -138,14 +152,14 @@ int main(int argc, char* argv[])
|
||||
logstr = ("Fourth write, no flush. Next flush only.");
|
||||
err = skygw_log_write(LOGFILE_ERROR, logstr);
|
||||
|
||||
err = skygw_log_flush(LOGFILE_ERROR);
|
||||
err = mxs_log_flush();
|
||||
|
||||
logstr = "My name is %s %d years and %d months.";
|
||||
#if !defined(SS_DEBUG)
|
||||
skygw_log_enable(LOGFILE_TRACE);
|
||||
#endif
|
||||
err = skygw_log_write(LOGFILE_TRACE, logstr, "TraceyTracey", 3, 7);
|
||||
skygw_log_flush(LOGFILE_TRACE);
|
||||
mxs_log_flush();
|
||||
#if !defined(SS_DEBUG)
|
||||
skygw_log_enable(LOGFILE_TRACE);
|
||||
#endif
|
||||
@ -156,7 +170,7 @@ int main(int argc, char* argv[])
|
||||
#endif
|
||||
logstr = "My name is Stacey %s";
|
||||
err = skygw_log_write_flush(LOGFILE_TRACE, logstr, " ");
|
||||
skygw_logmanager_done();
|
||||
mxs_log_finish();
|
||||
#if !defined(SS_DEBUG)
|
||||
skygw_log_enable(LOGFILE_TRACE);
|
||||
#endif
|
||||
@ -173,7 +187,7 @@ int main(int argc, char* argv[])
|
||||
logstr = "Ph%dlip.";
|
||||
err = skygw_log_write(LOGFILE_TRACE, logstr, 1);
|
||||
|
||||
skygw_logmanager_init("/tmp", log_argc, log_argv);
|
||||
mxs_log_init(NULL, "/tmp", LOG_TARGET_FS);
|
||||
logstr = ("A terrible error has occurred!");
|
||||
err = skygw_log_write_flush(LOGFILE_ERROR, logstr);
|
||||
|
||||
@ -195,7 +209,7 @@ int main(int argc, char* argv[])
|
||||
"with us. Just me and my mom - and you, of course. Then, if you wish, we could "
|
||||
"listen to the radio and keep company for our little Steven, my mom's cat, you know.");
|
||||
err = skygw_log_write(LOGFILE_MESSAGE, logstr);
|
||||
skygw_logmanager_done();
|
||||
mxs_log_finish();
|
||||
|
||||
#if defined(TEST1)
|
||||
mes = skygw_message_init();
|
||||
@ -238,7 +252,7 @@ int main(int argc, char* argv[])
|
||||
pthread_join(thr[i]->tid, NULL);
|
||||
}
|
||||
/** This is to release memory */
|
||||
skygw_logmanager_done();
|
||||
mxs_log_finish();
|
||||
|
||||
simple_mutex_unlock(mtx);
|
||||
|
||||
@ -295,7 +309,7 @@ int main(int argc, char* argv[])
|
||||
pthread_join(thr[i]->tid, NULL);
|
||||
}
|
||||
/** This is to release memory */
|
||||
skygw_logmanager_done();
|
||||
mxs_log_finish();
|
||||
|
||||
simple_mutex_unlock(mtx);
|
||||
|
||||
@ -319,20 +333,20 @@ int main(int argc, char* argv[])
|
||||
#if !defined(SS_DEBUG)
|
||||
skygw_log_enable(LOGFILE_TRACE);
|
||||
#endif
|
||||
succp = mxs_log_init(NULL, "/tmp", LOG_TARGET_FS);
|
||||
ss_dassert(succp);
|
||||
|
||||
logstr = ("\tTEST 3 - test enabling and disabling logs.");
|
||||
err = skygw_log_write(LOGFILE_ERROR, logstr);
|
||||
ss_dassert(err == 0);
|
||||
|
||||
succp = skygw_logmanager_init("/tmp", log_argc, log_argv);
|
||||
ss_dassert(succp);
|
||||
|
||||
skygw_log_disable(LOGFILE_TRACE);
|
||||
|
||||
logstr = ("1.\tWrite once to ERROR and twice to MESSAGE log.");
|
||||
err = skygw_log_write(LOGFILE_MESSAGE, logstr);
|
||||
ss_dassert(err == 0);
|
||||
err = skygw_log_write(LOGFILE_TRACE, logstr);
|
||||
ss_dassert(err != 0); /**< Must fail */
|
||||
ss_dassert(err == 0);
|
||||
err = skygw_log_write(LOGFILE_ERROR, logstr);
|
||||
ss_dassert(err == 0);
|
||||
|
||||
@ -355,18 +369,18 @@ int main(int argc, char* argv[])
|
||||
err = skygw_log_write(LOGFILE_TRACE, logstr);
|
||||
ss_dassert(err == 0);
|
||||
err = skygw_log_write(LOGFILE_ERROR, logstr);
|
||||
ss_dassert(err != 0); /**< Must fail */
|
||||
ss_dassert(err == 0);
|
||||
|
||||
skygw_log_disable(LOGFILE_MESSAGE);
|
||||
skygw_log_disable(LOGFILE_TRACE);
|
||||
|
||||
logstr = ("4.\tWrite to none.");
|
||||
err = skygw_log_write(LOGFILE_MESSAGE, logstr);
|
||||
ss_dassert(err != 0); /**< Must fail */
|
||||
ss_dassert(err == 0);
|
||||
err = skygw_log_write(LOGFILE_TRACE, logstr);
|
||||
ss_dassert(err != 0); /**< Must fail */
|
||||
ss_dassert(err == 0);
|
||||
err = skygw_log_write(LOGFILE_ERROR, logstr);
|
||||
ss_dassert(err != 0); /**< Must fail */
|
||||
ss_dassert(err == 0);
|
||||
|
||||
skygw_log_enable(LOGFILE_ERROR);
|
||||
skygw_log_enable(LOGFILE_MESSAGE);
|
||||
@ -375,16 +389,16 @@ int main(int argc, char* argv[])
|
||||
err = skygw_log_write(LOGFILE_MESSAGE, logstr);
|
||||
ss_dassert(err == 0);
|
||||
err = skygw_log_write(LOGFILE_TRACE, logstr);
|
||||
ss_dassert(err != 0); /**< Must fail */
|
||||
ss_dassert(err == 0);
|
||||
err = skygw_log_write(LOGFILE_ERROR, logstr);
|
||||
ss_dassert(err == 0);
|
||||
|
||||
skygw_logmanager_done();
|
||||
mxs_log_finish();
|
||||
|
||||
#endif /* TEST 3 */
|
||||
|
||||
#if defined(TEST4)
|
||||
succp = skygw_logmanager_init("/tmp", log_argc, log_argv);
|
||||
succp = mxs_log_init(NULL, "/tmp", LOG_TARGET_FS);
|
||||
ss_dassert(succp);
|
||||
#if !defined(SS_DEBUG)
|
||||
skygw_log_enable(LOGFILE_TRACE);
|
||||
@ -401,6 +415,7 @@ int main(int argc, char* argv[])
|
||||
err = skygw_log_write(LOGFILE_MESSAGE, logstr);
|
||||
ss_dassert(err == 0);
|
||||
|
||||
skygw_log_enable(LOGFILE_TRACE);
|
||||
logstr = ("3.\tWrite to TRACE log only.");
|
||||
err = skygw_log_write(LOGFILE_TRACE, logstr);
|
||||
ss_dassert(err == 0);
|
||||
@ -415,11 +430,11 @@ int main(int argc, char* argv[])
|
||||
logstr = ("5.\tThis should not appear anywhere since MESSAGE "
|
||||
"is disabled.");
|
||||
err = skygw_log_write(LOGFILE_MESSAGE, logstr);
|
||||
ss_dassert(err != 0);
|
||||
ss_dassert(err == 0);
|
||||
|
||||
skygw_logmanager_done();
|
||||
mxs_log_finish();
|
||||
|
||||
succp = skygw_logmanager_init("/tmp", log_argc, log_argv);
|
||||
succp = mxs_log_init(NULL, "/tmp", LOG_TARGET_FS);
|
||||
ss_dassert(succp);
|
||||
#if !defined(SS_DEBUG)
|
||||
skygw_log_enable(LOGFILE_TRACE);
|
||||
@ -447,7 +462,7 @@ int main(int argc, char* argv[])
|
||||
logstr = ("10.\tThis should not appear anywhere since MESSAGE is "
|
||||
"disabled.");
|
||||
err = skygw_log_write_flush(LOGFILE_MESSAGE, logstr);
|
||||
ss_dassert(err != 0);
|
||||
ss_dassert(err == 0);
|
||||
|
||||
skygw_log_enable(LOGFILE_MESSAGE);
|
||||
|
||||
@ -473,7 +488,7 @@ int main(int argc, char* argv[])
|
||||
|
||||
ss_dassert(err == 0);
|
||||
|
||||
skygw_logmanager_done();
|
||||
mxs_log_finish();
|
||||
|
||||
#endif /* TEST 4 */
|
||||
fprintf(stderr, ".. done.\n");
|
||||
@ -492,20 +507,18 @@ static void* thr_run(void* data)
|
||||
char* logstr;
|
||||
int err;
|
||||
|
||||
skygw_logmanager_init("/tmp", 0, NULL);
|
||||
skygw_logmanager_done();
|
||||
skygw_log_flush(LOGFILE_MESSAGE);
|
||||
mxs_log_init(NULL, "/tmp", LOG_TARGET_FS);
|
||||
mxs_log_flush();
|
||||
logstr = ("Hi, how are you?");
|
||||
err = skygw_log_write(LOGFILE_MESSAGE, logstr);
|
||||
|
||||
if (err != 0)
|
||||
{
|
||||
fprintf(stderr,"Error, log write failed.\n");
|
||||
TEST_ERROR("Error, log write failed.");
|
||||
}
|
||||
ss_dassert(err == 0);
|
||||
skygw_logmanager_done();
|
||||
skygw_log_flush(LOGFILE_TRACE);
|
||||
skygw_log_flush(LOGFILE_MESSAGE);
|
||||
mxs_log_finish();
|
||||
mxs_log_flush();
|
||||
logstr = ("I was wondering, you know, it has been such a lovely weather whole morning and "
|
||||
"I thought that would you like to come to my place and have a little piece of "
|
||||
"cheese with us. Just me and my mom - and you, of course. Then, if you wish, "
|
||||
@ -513,32 +526,34 @@ static void* thr_run(void* data)
|
||||
"cat, you know.");
|
||||
if (err != 0)
|
||||
{
|
||||
fprintf(stderr,"Error, log write failed.\n");
|
||||
TEST_ERROR("Error, log write failed.");
|
||||
}
|
||||
ss_dassert(err == 0);
|
||||
err = skygw_log_write(LOGFILE_MESSAGE, logstr);
|
||||
skygw_logmanager_init("/tmp", 0, NULL);
|
||||
mxs_log_init(NULL, "/tmp", LOG_TARGET_FS);
|
||||
logstr = ("Testing. One, two, three\n");
|
||||
err = skygw_log_write(LOGFILE_ERROR, logstr);
|
||||
if (err != 0)
|
||||
{
|
||||
fprintf(stderr,"Error, log write failed.\n");
|
||||
TEST_ERROR("Error, log write failed.");
|
||||
}
|
||||
ss_dassert(err == 0);
|
||||
skygw_logmanager_init("/tmp", 0, NULL);
|
||||
skygw_logmanager_init("/tmp", 0, NULL);
|
||||
skygw_log_flush(LOGFILE_ERROR);
|
||||
mxs_log_init(NULL, "/tmp", LOG_TARGET_FS);
|
||||
mxs_log_init(NULL, "/tmp", LOG_TARGET_FS);
|
||||
mxs_log_flush();
|
||||
logstr = ("For automatic and register variables, it is done each time the function or block is entered.");
|
||||
|
||||
#if !defined(SS_DEBUG)
|
||||
skygw_log_enable(LOGFILE_TRACE);
|
||||
#endif
|
||||
err = skygw_log_write(LOGFILE_TRACE, logstr);
|
||||
if (err != 0)
|
||||
{
|
||||
fprintf(stderr,"Error, log write failed.\n");
|
||||
TEST_ERROR("Error, log write failed.");
|
||||
}
|
||||
ss_dassert(err == 0);
|
||||
skygw_logmanager_done();
|
||||
skygw_logmanager_init("/tmp", 0, NULL);
|
||||
mxs_log_finish();
|
||||
mxs_log_init(NULL, "/tmp", LOG_TARGET_FS);
|
||||
logstr = ("Rather more surprising, at least at first sight, is the fact that a reference "
|
||||
"to a[i] can also be written as *(a+i). In evaluating a[i], C converts it to *(a+i) "
|
||||
"immediately; the two forms are equivalent. Applying the operatos & to both parts "
|
||||
@ -547,23 +562,23 @@ static void* thr_run(void* data)
|
||||
err = skygw_log_write(LOGFILE_ERROR, logstr);
|
||||
if (err != 0)
|
||||
{
|
||||
fprintf(stderr,"Error, log write failed.\n");
|
||||
TEST_ERROR("Error, log write failed.");
|
||||
}
|
||||
ss_dassert(err == 0);
|
||||
skygw_logmanager_init("/tmp", 0, NULL);
|
||||
skygw_logmanager_done();
|
||||
skygw_log_flush(LOGFILE_ERROR);
|
||||
skygw_logmanager_done();
|
||||
skygw_logmanager_done();
|
||||
mxs_log_init(NULL, "/tmp", LOG_TARGET_FS);
|
||||
mxs_log_finish();
|
||||
mxs_log_flush();
|
||||
mxs_log_finish();
|
||||
mxs_log_init(NULL, "/tmp", LOG_TARGET_FS);
|
||||
logstr = ("..and you?");
|
||||
err = skygw_log_write(LOGFILE_MESSAGE, logstr);
|
||||
if (err != 0)
|
||||
{
|
||||
fprintf(stderr,"Error, log write failed.\n");
|
||||
TEST_ERROR("Error, log write failed.");
|
||||
}
|
||||
ss_dassert(err == 0);
|
||||
skygw_logmanager_init("/tmp", 0, NULL);
|
||||
skygw_logmanager_init("/tmp", 0, NULL);
|
||||
mxs_log_finish();
|
||||
mxs_log_init(NULL, "/tmp", LOG_TARGET_FS);
|
||||
logstr = ("For automatic and register variables, it is done each time the function or block is entered.");
|
||||
#if !defined(SS_DEBUG)
|
||||
skygw_log_enable(LOGFILE_TRACE);
|
||||
@ -571,10 +586,10 @@ static void* thr_run(void* data)
|
||||
err = skygw_log_write(LOGFILE_TRACE, logstr);
|
||||
if (err != 0)
|
||||
{
|
||||
fprintf(stderr,"Error, log write failed.\n");
|
||||
TEST_ERROR("Error, log write failed.");
|
||||
}
|
||||
ss_dassert(err == 0);
|
||||
skygw_logmanager_init("/tmp", 0, NULL);
|
||||
mxs_log_init(NULL, "/tmp", LOG_TARGET_FS);
|
||||
logstr = ("Rather more surprising, at least at first sight, is the fact that a reference to "
|
||||
"a[i] can also be written as *(a+i). In evaluating a[i], C converts it to *(a+i) "
|
||||
"immediately; the two forms are equivalent. Applying the operatos & to both parts "
|
||||
@ -583,22 +598,23 @@ static void* thr_run(void* data)
|
||||
err = skygw_log_write(LOGFILE_ERROR, logstr);
|
||||
if (err != 0)
|
||||
{
|
||||
fprintf(stderr,"Error, log write failed.\n");
|
||||
TEST_ERROR("Error, log write failed.");
|
||||
}
|
||||
ss_dassert(err == 0);
|
||||
skygw_logmanager_init("/tmp", 0, NULL);
|
||||
mxs_log_init(NULL, "/tmp", LOG_TARGET_FS);
|
||||
logstr = ("..... and you too?");
|
||||
err = skygw_log_write(LOGFILE_MESSAGE, logstr);
|
||||
if (err != 0)
|
||||
{
|
||||
fprintf(stderr,"Error, log write failed.\n");
|
||||
TEST_ERROR("Error, log write failed.");
|
||||
}
|
||||
ss_dassert(err == 0);
|
||||
skygw_logmanager_done();
|
||||
mxs_log_finish();
|
||||
mxs_log_init(NULL, "/tmp", LOG_TARGET_FS);
|
||||
#if !defined(SS_DEBUG)
|
||||
skygw_log_enable(LOGFILE_TRACE);
|
||||
#endif
|
||||
skygw_log_flush(LOGFILE_TRACE);
|
||||
mxs_log_flush();
|
||||
logstr = ("For automatic and register variables, it is done each time the function or block is entered.");
|
||||
#if !defined(SS_DEBUG)
|
||||
skygw_log_enable(LOGFILE_TRACE);
|
||||
@ -606,28 +622,30 @@ static void* thr_run(void* data)
|
||||
err = skygw_log_write(LOGFILE_TRACE, logstr);
|
||||
if (err != 0)
|
||||
{
|
||||
fprintf(stderr,"Error, log write failed.\n");
|
||||
TEST_ERROR("Error, log write failed.");
|
||||
}
|
||||
ss_dassert(err == 0);
|
||||
skygw_logmanager_done();
|
||||
mxs_log_finish();
|
||||
mxs_log_init(NULL, "/tmp", LOG_TARGET_FS);
|
||||
logstr = ("Testing. One, two, three, four\n");
|
||||
err = skygw_log_write(LOGFILE_ERROR, logstr);
|
||||
if (err != 0)
|
||||
{
|
||||
fprintf(stderr,"Error, log write failed.\n");
|
||||
TEST_ERROR("Error, log write failed.");
|
||||
}
|
||||
ss_dassert(err == 0);
|
||||
skygw_logmanager_init("/tmp", 0, NULL);
|
||||
mxs_log_finish();
|
||||
mxs_log_init(NULL, "/tmp", LOG_TARGET_FS);
|
||||
logstr = ("Testing. One, two, three, .. where was I?\n");
|
||||
err = skygw_log_write(LOGFILE_ERROR, logstr);
|
||||
if (err != 0)
|
||||
{
|
||||
fprintf(stderr,"Error, log write failed.\n");
|
||||
TEST_ERROR("Error, log write failed.");
|
||||
}
|
||||
ss_dassert(err == 0);
|
||||
skygw_logmanager_init("/tmp", 0, NULL);
|
||||
skygw_logmanager_init("/tmp", 0, NULL);
|
||||
skygw_logmanager_done();
|
||||
mxs_log_finish();
|
||||
mxs_log_init(NULL, "/tmp", LOG_TARGET_FS);
|
||||
mxs_log_finish();
|
||||
simple_mutex_lock(td->mtx, true);
|
||||
*td->nactive -= 1;
|
||||
simple_mutex_unlock(td->mtx);
|
||||
|
@ -31,7 +31,6 @@ int main(int argc, char** argv)
|
||||
char cwd[1024];
|
||||
char tmp[2048];
|
||||
char *message;
|
||||
char** optstr;
|
||||
long msg_index = 1;
|
||||
struct timespec ts1;
|
||||
ts1.tv_sec = 0;
|
||||
@ -55,7 +54,6 @@ int main(int argc, char** argv)
|
||||
}
|
||||
|
||||
if (getcwd(cwd, sizeof(cwd)) == NULL ||
|
||||
(optstr = (char**)malloc(sizeof(char*) * 4)) == NULL ||
|
||||
(message = (char*)malloc(sizeof(char) * block_size)) == NULL)
|
||||
{
|
||||
fprintf(stderr,"Fatal Error, exiting...");
|
||||
@ -65,13 +63,11 @@ int main(int argc, char** argv)
|
||||
memset(tmp, 0, 1024);
|
||||
|
||||
sprintf(tmp, "%s", cwd);
|
||||
optstr[0] = strdup("log_manager");
|
||||
optstr[1] = NULL;
|
||||
|
||||
iterations = atoi(argv[1]);
|
||||
interval = atoi(argv[2]);
|
||||
|
||||
succp = skygw_logmanager_init(tmp, 1, optstr);
|
||||
succp = mxs_log_init(NULL, tmp, LOG_TARGET_FS);
|
||||
|
||||
if (!succp)
|
||||
{
|
||||
@ -111,13 +107,8 @@ int main(int argc, char** argv)
|
||||
nanosleep(&ts1, NULL);
|
||||
}
|
||||
|
||||
skygw_log_flush(LOGFILE_ERROR);
|
||||
skygw_logmanager_done();
|
||||
mxs_log_flush();
|
||||
mxs_log_finish();
|
||||
free(message);
|
||||
free(optstr[0]);
|
||||
free(optstr[1]);
|
||||
free(optstr[2]);
|
||||
free(optstr[3]);
|
||||
free(optstr);
|
||||
return 0;
|
||||
}
|
||||
|
4286
server/core/config.c
4286
server/core/config.c
File diff suppressed because it is too large
Load Diff
@ -90,12 +90,28 @@
|
||||
ON user.user=db.user AND user.host=db.host \
|
||||
WHERE user.user IS NOT NULL" MYSQL_USERS_WITH_DB_ORDER
|
||||
|
||||
#define LOAD_MYSQL57_USERS_WITH_DB_QUERY "SELECT \
|
||||
user.user AS user, \
|
||||
user.host AS host, \
|
||||
user.authentication_string AS password, \
|
||||
concat(user.user,user.host,user.authentication_string,user.Select_priv,IFNULL(db,'')) AS userdata, \
|
||||
user.Select_priv AS anydb, \
|
||||
db.db AS db \
|
||||
FROM mysql.user LEFT JOIN mysql.db \
|
||||
ON user.user=db.user AND user.host=db.host \
|
||||
WHERE user.user IS NOT NULL" MYSQL_USERS_WITH_DB_ORDER
|
||||
|
||||
#define MYSQL_USERS_WITH_DB_COUNT "SELECT COUNT(1) AS nusers_db FROM (" LOAD_MYSQL_USERS_WITH_DB_QUERY ") AS tbl_count"
|
||||
#define MYSQL57_USERS_WITH_DB_COUNT "SELECT COUNT(1) AS nusers_db FROM (" LOAD_MYSQL57_USERS_WITH_DB_QUERY ") AS tbl_count"
|
||||
|
||||
#define LOAD_MYSQL_USERS_WITH_DB_QUERY_NO_ROOT "SELECT * \
|
||||
FROM (" LOAD_MYSQL_USERS_WITH_DB_QUERY ") AS t1 \
|
||||
WHERE user NOT IN ('root')" MYSQL_USERS_WITH_DB_ORDER
|
||||
|
||||
#define LOAD_MYSQL57_USERS_WITH_DB_QUERY_NO_ROOT "SELECT * \
|
||||
FROM (" LOAD_MYSQL57_USERS_WITH_DB_QUERY ") AS t1 \
|
||||
WHERE user NOT IN ('root')" MYSQL_USERS_WITH_DB_ORDER
|
||||
|
||||
#define LOAD_MYSQL_DATABASE_NAMES "SELECT * \
|
||||
FROM ( (SELECT COUNT(1) AS ndbs \
|
||||
FROM INFORMATION_SCHEMA.SCHEMATA) AS tbl1, \
|
||||
@ -133,6 +149,39 @@ int add_wildcard_users(USERS *users,
|
||||
|
||||
static int gw_mysql_set_timeouts(MYSQL* handle);
|
||||
|
||||
/**
|
||||
* Get the user data query.
|
||||
* @param server_version Server version string
|
||||
* @param include_root Include root user
|
||||
* @return Users query
|
||||
*/
|
||||
const char* get_mysql_users_query(char* server_version, bool include_root)
|
||||
{
|
||||
const char* rval;
|
||||
if (strstr(server_version, "5.7."))
|
||||
{
|
||||
rval = include_root ? LOAD_MYSQL57_USERS_WITH_DB_QUERY :
|
||||
LOAD_MYSQL57_USERS_WITH_DB_QUERY_NO_ROOT;
|
||||
}
|
||||
else
|
||||
{
|
||||
rval = include_root ? LOAD_MYSQL_USERS_WITH_DB_QUERY :
|
||||
LOAD_MYSQL_USERS_WITH_DB_QUERY_NO_ROOT;
|
||||
}
|
||||
return rval;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the user count query.
|
||||
* @param server_version Server version string
|
||||
* @return User vount query
|
||||
* */
|
||||
const char* get_mysq_users_db_count_query(char* server_version)
|
||||
{
|
||||
return strstr(server_version, "5.7.") ?
|
||||
MYSQL57_USERS_WITH_DB_COUNT : MYSQL_USERS_WITH_DB_COUNT;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the IP address of the user matches the one in the grant. This assumes
|
||||
* that the grant has one or more single-character wildcards in it.
|
||||
@ -651,7 +700,8 @@ getAllUsers(SERVICE *service, USERS *users)
|
||||
char *dpwd = NULL;
|
||||
int total_users = 0;
|
||||
SERVER_REF *server;
|
||||
char *users_query, *tmp;
|
||||
const char *users_query;
|
||||
char *tmp;
|
||||
unsigned char hash[SHA_DIGEST_LENGTH]="";
|
||||
char *users_data = NULL;
|
||||
char *final_data = NULL;
|
||||
@ -825,9 +875,19 @@ getAllUsers(SERVICE *service, USERS *users)
|
||||
mysql_close(con);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
|
||||
if (server->server->server_string == NULL)
|
||||
{
|
||||
const char *server_string = mysql_get_server_info(con);
|
||||
if (!server_set_version_string(server->server, server_string))
|
||||
{
|
||||
mysql_close(con);
|
||||
goto cleanup;
|
||||
}
|
||||
}
|
||||
/** Count users. Start with users and db grants for users */
|
||||
if (mysql_query(con, MYSQL_USERS_WITH_DB_COUNT)) {
|
||||
const char *user_with_db_count = get_mysq_users_db_count_query(server->server->server_string);
|
||||
if (mysql_query(con, user_with_db_count)) {
|
||||
if (mysql_errno(con) != ER_TABLEACCESS_DENIED_ERROR) {
|
||||
/* This is an error we cannot handle, return */
|
||||
LOGIF(LE, (skygw_log_write_flush(
|
||||
@ -883,13 +943,10 @@ getAllUsers(SERVICE *service, USERS *users)
|
||||
mysql_close(con);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if(service->enable_root) {
|
||||
/* enable_root for MySQL protocol module means load the root user credentials from backend databases */
|
||||
users_query = LOAD_MYSQL_USERS_WITH_DB_QUERY;
|
||||
} else {
|
||||
users_query = LOAD_MYSQL_USERS_WITH_DB_QUERY_NO_ROOT;
|
||||
}
|
||||
|
||||
users_query = get_mysql_users_query(server->server->server_string,
|
||||
service->enable_root);
|
||||
|
||||
|
||||
/* send first the query that fetches users and db grants */
|
||||
if (mysql_query(con, users_query)) {
|
||||
@ -1197,7 +1254,7 @@ getUsers(SERVICE *service, USERS *users)
|
||||
char *dpwd;
|
||||
int total_users = 0;
|
||||
SERVER_REF *server;
|
||||
char *users_query;
|
||||
const char *users_query;
|
||||
unsigned char hash[SHA_DIGEST_LENGTH]="";
|
||||
char *users_data = NULL;
|
||||
int nusers = 0;
|
||||
@ -1343,10 +1400,21 @@ getUsers(SERVICE *service, USERS *users)
|
||||
service->name)));
|
||||
mysql_close(con);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
if (server->server->server_string == NULL)
|
||||
{
|
||||
const char *server_string = mysql_get_server_info(con);
|
||||
if (!server_set_version_string(server->server, server_string))
|
||||
{
|
||||
mysql_close(con);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
const char *user_with_db_count = get_mysq_users_db_count_query(server->server->server_string);
|
||||
/** Count users. Start with users and db grants for users */
|
||||
if (mysql_query(con, MYSQL_USERS_WITH_DB_COUNT)) {
|
||||
if (mysql_query(con, user_with_db_count)) {
|
||||
if (mysql_errno(con) != ER_TABLEACCESS_DENIED_ERROR) {
|
||||
/* This is an error we cannot handle, return */
|
||||
LOGIF(LE, (skygw_log_write_flush(
|
||||
@ -1403,13 +1471,8 @@ getUsers(SERVICE *service, USERS *users)
|
||||
return -1;
|
||||
}
|
||||
|
||||
if(service->enable_root) {
|
||||
/* enable_root for MySQL protocol module means load the root user credentials from backend databases */
|
||||
users_query = LOAD_MYSQL_USERS_WITH_DB_QUERY;
|
||||
} else {
|
||||
users_query = LOAD_MYSQL_USERS_WITH_DB_QUERY_NO_ROOT;
|
||||
}
|
||||
|
||||
users_query = get_mysql_users_query(server->server->server_string,
|
||||
service->enable_root);
|
||||
/* send first the query that fetches users and db grants */
|
||||
if (mysql_query(con, users_query)) {
|
||||
/*
|
||||
|
@ -1052,7 +1052,7 @@ int dcb_read_SSL(DCB *dcb,
|
||||
|
||||
if (GWBUF_LENGTH(buffer) != n)
|
||||
{
|
||||
skygw_log_sync_all();
|
||||
mxs_log_flush_sync();
|
||||
}
|
||||
|
||||
ss_info_dassert((buffer->start <= buffer->end), "Buffer start has passed end.");
|
||||
|
@ -6,15 +6,17 @@
|
||||
* @param argv Array of char pointers to be filled with tokenized arguments
|
||||
* @return 0 on success, -1 on error
|
||||
*/
|
||||
int tokenize_arguments(char* args, char** argv)
|
||||
int tokenize_arguments(char* argstr, char** argv)
|
||||
{
|
||||
int i = 0;
|
||||
bool quoted = false;
|
||||
bool read = false;
|
||||
bool escaped = false;
|
||||
char *ptr,*start;
|
||||
char args[strlen(argstr)];
|
||||
char qc;
|
||||
|
||||
strcpy(args, argstr);
|
||||
start = args;
|
||||
ptr = start;
|
||||
|
||||
@ -80,36 +82,40 @@ int tokenize_arguments(char* args, char** argv)
|
||||
*/
|
||||
EXTERNCMD* externcmd_allocate(char* argstr)
|
||||
{
|
||||
EXTERNCMD* cmd;
|
||||
EXTERNCMD* cmd = (EXTERNCMD*) malloc(sizeof(EXTERNCMD));
|
||||
char** argv = (char**) malloc(sizeof(char*) * MAXSCALE_EXTCMD_ARG_MAX);
|
||||
|
||||
if(argstr == NULL)
|
||||
return NULL;
|
||||
|
||||
if((cmd = (EXTERNCMD*)malloc(sizeof(EXTERNCMD))) != NULL)
|
||||
if (argstr && cmd && argv)
|
||||
{
|
||||
if(tokenize_arguments(argstr,cmd->parameters) == -1)
|
||||
{
|
||||
free(cmd);
|
||||
return NULL;
|
||||
}
|
||||
if(access(cmd->parameters[0],F_OK) != 0)
|
||||
{
|
||||
skygw_log_write(LE,
|
||||
"Error: Cannot find file: %s",
|
||||
cmd->parameters[0]);
|
||||
externcmd_free(cmd);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if(access(cmd->parameters[0],X_OK) != 0)
|
||||
{
|
||||
skygw_log_write(LE,
|
||||
"Error: Cannot execute file '%s'. Missing execution permissions.",
|
||||
cmd->parameters[0]);
|
||||
externcmd_free(cmd);
|
||||
return NULL;
|
||||
}
|
||||
skygw_log_write(LT, "Executing script %s.", cmd->parameters[0]);
|
||||
cmd->argv = argv;
|
||||
if (tokenize_arguments(argstr, cmd->argv) == 0)
|
||||
{
|
||||
if (access(cmd->argv[0], X_OK) != 0)
|
||||
{
|
||||
if (access(cmd->argv[0], F_OK) != 0)
|
||||
{
|
||||
skygw_log_write(LE, "Cannot find file: %s", cmd->argv[0]);
|
||||
}
|
||||
else
|
||||
{
|
||||
skygw_log_write(LE, "Cannot execute file '%s'. Missing "
|
||||
"execution permissions.", cmd->argv[0]);
|
||||
}
|
||||
externcmd_free(cmd);
|
||||
cmd = NULL;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
externcmd_free(cmd);
|
||||
cmd = NULL;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
free(cmd);
|
||||
free(argv);
|
||||
cmd = NULL;
|
||||
}
|
||||
return cmd;
|
||||
}
|
||||
@ -120,13 +126,15 @@ EXTERNCMD* externcmd_allocate(char* argstr)
|
||||
*/
|
||||
void externcmd_free(EXTERNCMD* cmd)
|
||||
{
|
||||
int i;
|
||||
|
||||
for(i = 0;cmd->parameters[i] != NULL;i++)
|
||||
if (cmd)
|
||||
{
|
||||
free(cmd->parameters[i]);
|
||||
for (int i = 0; cmd->argv[i]; i++)
|
||||
{
|
||||
free(cmd->argv[i]);
|
||||
}
|
||||
free(cmd->argv);
|
||||
free(cmd);
|
||||
}
|
||||
free(cmd);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -138,29 +146,141 @@ int externcmd_execute(EXTERNCMD* cmd)
|
||||
{
|
||||
int rval = 0;
|
||||
pid_t pid;
|
||||
|
||||
|
||||
pid = fork();
|
||||
|
||||
if(pid < 0)
|
||||
if (pid < 0)
|
||||
{
|
||||
char errbuf[STRERROR_BUFLEN];
|
||||
skygw_log_write(LOGFILE_ERROR,"Error: Failed to execute command '%s', fork failed: [%d] %s",
|
||||
cmd->parameters[0],errno,strerror_r(errno, errbuf, sizeof(errbuf)));
|
||||
skygw_log_write(LOGFILE_ERROR, "Failed to execute command '%s', fork failed: [%d] %s",
|
||||
cmd->argv[0], errno, strerror_r(errno, errbuf, sizeof(errbuf)));
|
||||
rval = -1;
|
||||
}
|
||||
else if(pid == 0)
|
||||
else if (pid == 0)
|
||||
{
|
||||
/** Child process, execute command */
|
||||
execvp(cmd->parameters[0],cmd->parameters);
|
||||
_exit(1);
|
||||
execvp(cmd->argv[0], cmd->argv);
|
||||
_exit(1);
|
||||
}
|
||||
else
|
||||
{
|
||||
cmd->child = pid;
|
||||
cmd->n_exec++;
|
||||
LOGIF(LD,skygw_log_write(LD,"[monitor_exec_cmd] Forked child process %d : %s.",pid,cmd));
|
||||
cmd->child = pid;
|
||||
cmd->n_exec++;
|
||||
LOGIF(LD, skygw_log_write(LD, "[monitor_exec_cmd] Forked child process %d : %s.", pid, cmd));
|
||||
}
|
||||
|
||||
return rval;
|
||||
}
|
||||
|
||||
/**
|
||||
* Substitute all occurrences of @c match with @c replace in the arguments for @c cmd.
|
||||
* @param cmd External command
|
||||
* @param match Match string
|
||||
* @param replace Replacement string
|
||||
* @return true if replacement was successful, false on error
|
||||
*/
|
||||
bool externcmd_substitute_arg(EXTERNCMD* cmd, const char* match, const char* replace)
|
||||
{
|
||||
int err;
|
||||
bool rval = true;
|
||||
size_t errpos;
|
||||
pcre2_code *re = pcre2_compile((PCRE2_SPTR) match, PCRE2_ZERO_TERMINATED, 0, &err, &errpos, NULL);
|
||||
if (re)
|
||||
{
|
||||
for (int i = 0; cmd->argv[i] && rval; i++)
|
||||
{
|
||||
size_t size = strlen(cmd->argv[i]);
|
||||
char* dest = malloc(size);
|
||||
if (dest)
|
||||
{
|
||||
mxs_pcre2_result_t rc = mxs_pcre2_substitute(re, cmd->argv[i], replace, &dest, &size);
|
||||
switch (rc)
|
||||
{
|
||||
case MXS_PCRE2_ERROR:
|
||||
free(dest);
|
||||
rval = false;
|
||||
break;
|
||||
case MXS_PCRE2_MATCH:
|
||||
free(cmd->argv[i]);
|
||||
cmd->argv[i] = dest;
|
||||
break;
|
||||
case MXS_PCRE2_NOMATCH:
|
||||
free(dest);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
rval = false;
|
||||
}
|
||||
return rval;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the name of the command being executed.
|
||||
*
|
||||
* This copies the command being executed into a new string.
|
||||
* @param str Command string, optionally with arguments
|
||||
* @return Command part of the string if arguments were defined
|
||||
*/
|
||||
char* get_command(const char* str)
|
||||
{
|
||||
char* rval = NULL;
|
||||
const char* start = str;
|
||||
|
||||
while (*start && isspace(*start))
|
||||
{
|
||||
start++;
|
||||
}
|
||||
|
||||
const char* end = start;
|
||||
|
||||
while (*end && !isspace(*end))
|
||||
{
|
||||
end++;
|
||||
}
|
||||
|
||||
size_t len = end - start;
|
||||
|
||||
if (len > 0 && (rval = malloc(len + 1)))
|
||||
{
|
||||
memcpy(rval, start, len);
|
||||
rval[len] = '\0';
|
||||
}
|
||||
|
||||
return rval;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a command can be executed.
|
||||
*
|
||||
* Checks if the file being executed exists and if the current user has execution
|
||||
* permissions on the file.
|
||||
* @param argstr Command to check. Can contain arguments for the command.
|
||||
* @return True if the file was found and the use has execution permissions to it.
|
||||
*/
|
||||
bool externcmd_can_execute(const char* argstr)
|
||||
{
|
||||
bool rval = false;
|
||||
char *command = get_command(argstr);
|
||||
|
||||
if (command)
|
||||
{
|
||||
if (access(command, X_OK) == 0)
|
||||
{
|
||||
rval = true;
|
||||
}
|
||||
else if (access(command, F_OK) == 0)
|
||||
{
|
||||
skygw_log_write(LE, "The executable cannot be executed: %s", command);
|
||||
}
|
||||
else
|
||||
{
|
||||
skygw_log_write(LE, "The executable cannot be found: %s", command);
|
||||
}
|
||||
free(command);
|
||||
}
|
||||
return rval;
|
||||
}
|
||||
|
@ -307,10 +307,7 @@ static void sigusr1_handler (int i)
|
||||
LOGIF(LM, (skygw_log_write(
|
||||
LOGFILE_MESSAGE,
|
||||
"Log file flush following reception of SIGUSR1\n")));
|
||||
skygw_log_rotate(LOGFILE_ERROR);
|
||||
skygw_log_rotate(LOGFILE_MESSAGE);
|
||||
skygw_log_rotate(LOGFILE_TRACE);
|
||||
skygw_log_rotate(LOGFILE_DEBUG);
|
||||
mxs_log_rotate();
|
||||
}
|
||||
|
||||
static void sigterm_handler (int i) {
|
||||
@ -319,7 +316,7 @@ static void sigterm_handler (int i) {
|
||||
skygw_log_write_flush(
|
||||
LOGFILE_ERROR,
|
||||
"MaxScale received signal SIGTERM. Exiting.");
|
||||
skygw_log_sync_all();
|
||||
mxs_log_flush_sync();
|
||||
shutdown_server();
|
||||
}
|
||||
|
||||
@ -331,7 +328,7 @@ sigint_handler (int i)
|
||||
skygw_log_write_flush(
|
||||
LOGFILE_ERROR,
|
||||
"MaxScale received signal SIGINT. Shutting down.");
|
||||
skygw_log_sync_all();
|
||||
mxs_log_flush_sync();
|
||||
shutdown_server();
|
||||
fprintf(stderr, "\n\nShutting down MaxScale\n\n");
|
||||
}
|
||||
@ -412,7 +409,7 @@ sigfatal_handler(int i)
|
||||
}
|
||||
}
|
||||
|
||||
skygw_log_sync_all();
|
||||
mxs_log_flush_sync();
|
||||
|
||||
/* re-raise signal to enforce core dump */
|
||||
fprintf(stderr, "\n\nWriting core dump\n");
|
||||
@ -825,7 +822,7 @@ static bool file_is_readable(
|
||||
absolute_pathname,
|
||||
eno,
|
||||
strerror_r(eno, errbuf, sizeof(errbuf)));
|
||||
skygw_log_sync_all();
|
||||
mxs_log_flush_sync();
|
||||
succp = false;
|
||||
}
|
||||
return succp;
|
||||
@ -1077,19 +1074,16 @@ int main(int argc, char **argv)
|
||||
char* tmp_path;
|
||||
char* tmp_var;
|
||||
int option_index;
|
||||
int logtofile = 0; /* Use shared memory or file */
|
||||
log_target_t log_target = LOG_TARGET_FS;
|
||||
int *syslog_enabled = &config_get_global_options()->syslog; /** Log to syslog */
|
||||
int *maxscalelog_enabled = &config_get_global_options()->maxlog; /** Log with MaxScale */
|
||||
ssize_t log_flush_timeout_ms = 0;
|
||||
sigset_t sigset;
|
||||
sigset_t sigpipe_mask;
|
||||
sigset_t saved_mask;
|
||||
void (*exitfunp[4])(void) = {skygw_logmanager_exit,
|
||||
datadir_cleanup,
|
||||
write_footer,
|
||||
NULL};
|
||||
void (*exitfunp[4])(void) = { mxs_log_finish, datadir_cleanup, write_footer, NULL };
|
||||
|
||||
*syslog_enabled = 0;
|
||||
*syslog_enabled = 1;
|
||||
*maxscalelog_enabled = 1;
|
||||
|
||||
sigemptyset(&sigpipe_mask);
|
||||
@ -1169,9 +1163,9 @@ int main(int argc, char **argv)
|
||||
|
||||
case 'l':
|
||||
if (strncasecmp(optarg, "file", PATH_MAX) == 0)
|
||||
logtofile = 1;
|
||||
log_target = LOG_TARGET_FS;
|
||||
else if (strncasecmp(optarg, "shm", PATH_MAX) == 0)
|
||||
logtofile = 0;
|
||||
log_target = LOG_TARGET_SHMEM;
|
||||
else
|
||||
{
|
||||
char* logerr = "Configuration file argument "
|
||||
@ -1698,13 +1692,8 @@ int main(int argc, char **argv)
|
||||
|
||||
/**
|
||||
* Init Log Manager for MaxScale.
|
||||
* The skygw_logmanager_init expects to take arguments as passed to main
|
||||
* and proesses them with getopt, therefore we need to give it a dummy
|
||||
* argv[0]
|
||||
*/
|
||||
{
|
||||
char buf[1024];
|
||||
char *argv[8];
|
||||
bool succp;
|
||||
|
||||
if (mkdir(get_logdir(), 0777) != 0 && errno != EEXIST)
|
||||
@ -1715,8 +1704,6 @@ int main(int argc, char **argv)
|
||||
goto return_main;
|
||||
}
|
||||
|
||||
argv[0] = "MaxScale";
|
||||
|
||||
if (!(*syslog_enabled))
|
||||
{
|
||||
printf("Syslog logging is disabled.\n");
|
||||
@ -1726,27 +1713,11 @@ int main(int argc, char **argv)
|
||||
{
|
||||
printf("MaxScale logging is disabled.\n");
|
||||
}
|
||||
logmanager_enable_syslog(*syslog_enabled);
|
||||
logmanager_enable_maxscalelog(*maxscalelog_enabled);
|
||||
|
||||
if (logtofile)
|
||||
{
|
||||
argv[1] = "-l"; /*< write to syslog */
|
||||
/** Logs that should be syslogged */
|
||||
argv[2] = "LOGFILE_MESSAGE,LOGFILE_ERROR"
|
||||
"LOGFILE_DEBUG,LOGFILE_TRACE";
|
||||
argv[3] = NULL;
|
||||
succp = skygw_logmanager_init(get_logdir(), 3, argv);
|
||||
}
|
||||
else
|
||||
{
|
||||
argv[1] = "-s"; /*< store to shared memory */
|
||||
argv[2] = "LOGFILE_DEBUG,LOGFILE_TRACE"; /*< to shm */
|
||||
argv[3] = "-l"; /*< write to syslog */
|
||||
argv[4] = "LOGFILE_MESSAGE,LOGFILE_ERROR"; /*< to syslog */
|
||||
argv[5] = NULL;
|
||||
succp = skygw_logmanager_init(get_logdir(), 5, argv);
|
||||
}
|
||||
mxs_log_set_syslog_enabled(*syslog_enabled);
|
||||
mxs_log_set_maxscalelog_enabled(*maxscalelog_enabled);
|
||||
|
||||
succp = mxs_log_init(NULL, get_logdir(), log_target);
|
||||
|
||||
if (!succp)
|
||||
{
|
||||
@ -2084,10 +2055,7 @@ static void log_flush_cb(
|
||||
LOGIF(LM, (skygw_log_write(LOGFILE_MESSAGE,
|
||||
"Started MaxScale log flusher.")));
|
||||
while (!do_exit) {
|
||||
skygw_log_flush(LOGFILE_ERROR);
|
||||
skygw_log_flush(LOGFILE_MESSAGE);
|
||||
skygw_log_flush(LOGFILE_TRACE);
|
||||
skygw_log_flush(LOGFILE_DEBUG);
|
||||
mxs_log_flush();
|
||||
nanosleep(&ts1, NULL);
|
||||
}
|
||||
LOGIF(LM, (skygw_log_write(LOGFILE_MESSAGE,
|
||||
@ -2375,7 +2343,7 @@ void set_log_augmentation(const char* value)
|
||||
|
||||
if (!augmentation_set)
|
||||
{
|
||||
skygw_log_set_augmentation(atoi(value));
|
||||
mxs_log_set_augmentation(atoi(value));
|
||||
|
||||
augmentation_set = true;
|
||||
}
|
||||
|
@ -148,6 +148,7 @@ hashtable_alloc_real(
|
||||
rval->vfreefn = nullfn;
|
||||
rval->n_readers = 0;
|
||||
rval->writelock = 0;
|
||||
rval->n_elements = 0;
|
||||
spinlock_init(&rval->spin);
|
||||
if ((rval->entries = (HASHENTRIES **)calloc(rval->hashsize, sizeof(HASHENTRIES *))) == NULL)
|
||||
{
|
||||
@ -296,6 +297,7 @@ hashtable_add(HASHTABLE *table, void *key, void *value)
|
||||
ptr->next = table->entries[hashkey % table->hashsize];
|
||||
table->entries[hashkey % table->hashsize] = ptr;
|
||||
}
|
||||
table->n_elements++;
|
||||
hashtable_write_unlock(table);
|
||||
|
||||
return 1;
|
||||
@ -362,6 +364,8 @@ HASHENTRIES *entry, *ptr;
|
||||
table->vfreefn(entry->value);
|
||||
free(entry);
|
||||
}
|
||||
table->n_elements--;
|
||||
assert(table->n_elements >= 0);
|
||||
hashtable_write_unlock(table);
|
||||
return 1;
|
||||
}
|
||||
@ -772,3 +776,17 @@ char buf[40];
|
||||
close(fd);
|
||||
return rval;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the number of elements added to the hashtable
|
||||
* @param table Hashtable to measure
|
||||
* @return Number of inserted elements or 0 if table is NULL
|
||||
*/
|
||||
int hashtable_size(HASHTABLE *table)
|
||||
{
|
||||
assert(table);
|
||||
spinlock_acquire(&table->spin);
|
||||
int rval = table->n_elements;
|
||||
spinlock_release(&table->spin);
|
||||
return rval;
|
||||
}
|
||||
|
@ -35,10 +35,7 @@
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
int arg_count = 1;
|
||||
char *home;
|
||||
char *keyfile;
|
||||
char** arg_vector;
|
||||
int rval = 0;
|
||||
|
||||
if (argc < 2)
|
||||
@ -50,18 +47,8 @@ int main(int argc, char **argv)
|
||||
{
|
||||
keyfile = argv[1];
|
||||
}
|
||||
arg_vector = malloc(sizeof(char*) * (arg_count + 1));
|
||||
|
||||
if (arg_vector == NULL)
|
||||
{
|
||||
fprintf(stderr,"Error: Memory allocation failed.\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
arg_vector[0] = "logmanager";
|
||||
arg_vector[1] = NULL;
|
||||
skygw_logmanager_init(NULL, arg_count, arg_vector);
|
||||
free(arg_vector);
|
||||
mxs_log_init(NULL, NULL, LOG_TARGET_DEFAULT);
|
||||
|
||||
if (secrets_writeKeys(keyfile))
|
||||
{
|
||||
@ -69,8 +56,8 @@ int main(int argc, char **argv)
|
||||
rval = 1;
|
||||
}
|
||||
|
||||
skygw_log_sync_all();
|
||||
skygw_logmanager_done();
|
||||
mxs_log_flush_sync();
|
||||
mxs_log_finish();
|
||||
|
||||
return rval;
|
||||
}
|
||||
|
@ -42,9 +42,7 @@ main(int argc, char **argv)
|
||||
{
|
||||
char *enc;
|
||||
char *pw;
|
||||
int arg_count = 1;
|
||||
char *home;
|
||||
char** arg_vector;
|
||||
int rval = 0;
|
||||
|
||||
if (argc != 3)
|
||||
@ -53,18 +51,7 @@ main(int argc, char **argv)
|
||||
return 1;
|
||||
}
|
||||
|
||||
arg_vector = malloc(sizeof(char*) * (arg_count + 1));
|
||||
|
||||
if (arg_vector == NULL)
|
||||
{
|
||||
fprintf(stderr,"Error: Memory allocation failed.\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
arg_vector[0] = "logmanager";
|
||||
arg_vector[1] = NULL;
|
||||
skygw_logmanager_init(NULL, arg_count, arg_vector);
|
||||
free(arg_vector);
|
||||
mxs_log_init(NULL, NULL, LOG_TARGET_DEFAULT);
|
||||
|
||||
pw = calloc(81, sizeof(char));
|
||||
|
||||
@ -87,7 +74,7 @@ main(int argc, char **argv)
|
||||
}
|
||||
|
||||
free(pw);
|
||||
skygw_log_sync_all();
|
||||
skygw_logmanager_done();
|
||||
mxs_log_flush_sync();
|
||||
mxs_log_finish();
|
||||
return rval;
|
||||
}
|
||||
|
@ -84,6 +84,7 @@ MONITOR *mon;
|
||||
mon->write_timeout = DEFAULT_WRITE_TIMEOUT;
|
||||
mon->connect_timeout = DEFAULT_CONNECT_TIMEOUT;
|
||||
mon->interval = MONITOR_INTERVAL;
|
||||
mon->parameters = NULL;
|
||||
spinlock_init(&mon->lock);
|
||||
spinlock_acquire(&monLock);
|
||||
mon->next = allMonitors;
|
||||
@ -118,6 +119,7 @@ MONITOR *ptr;
|
||||
ptr->next = mon->next;
|
||||
}
|
||||
spinlock_release(&monLock);
|
||||
free_config_parameter(mon->parameters);
|
||||
free(mon->name);
|
||||
free(mon);
|
||||
}
|
||||
@ -137,6 +139,23 @@ monitorStart(MONITOR *monitor, void* params)
|
||||
spinlock_release(&monitor->lock);
|
||||
}
|
||||
|
||||
/**
|
||||
* Start all monitors
|
||||
*/
|
||||
void monitorStartAll()
|
||||
{
|
||||
MONITOR *ptr;
|
||||
|
||||
spinlock_acquire(&monLock);
|
||||
ptr = allMonitors;
|
||||
while (ptr)
|
||||
{
|
||||
monitorStart(ptr, ptr->parameters);
|
||||
ptr = ptr->next;
|
||||
}
|
||||
spinlock_release(&monLock);
|
||||
}
|
||||
|
||||
/**
|
||||
* Stop a given monitor
|
||||
*
|
||||
@ -522,3 +541,22 @@ bool check_monitor_permissions(MONITOR* monitor)
|
||||
free(dpasswd);
|
||||
return rval;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add parameters to the monitor
|
||||
* @param monitor Monitor
|
||||
* @param params Config parameters
|
||||
*/
|
||||
void monitorAddParameters(MONITOR *monitor, CONFIG_PARAMETER *params)
|
||||
{
|
||||
while (params)
|
||||
{
|
||||
CONFIG_PARAMETER* clone = config_clone_param(params);
|
||||
if (clone)
|
||||
{
|
||||
clone->next = monitor->parameters;
|
||||
monitor->parameters = clone;
|
||||
}
|
||||
params = params->next;
|
||||
}
|
||||
}
|
||||
|
@ -1,413 +1,408 @@
|
||||
/*
|
||||
* 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
|
||||
*/
|
||||
|
||||
#include <secrets.h>
|
||||
#include <time.h>
|
||||
#include <skygw_utils.h>
|
||||
#include <log_manager.h>
|
||||
#include <ctype.h>
|
||||
#include <mysql_client_server_protocol.h>
|
||||
#include <gwdirs.h>
|
||||
#include <random_jkiss.h>
|
||||
|
||||
/**
|
||||
* Generate a random printable character
|
||||
*
|
||||
* @return A random printable character
|
||||
*/
|
||||
static unsigned char
|
||||
secrets_randomchar()
|
||||
{
|
||||
return (char)((random_jkiss() % ('~' - ' ')) + ' ');
|
||||
}
|
||||
|
||||
static int
|
||||
secrets_random_str(unsigned char *output, int len)
|
||||
{
|
||||
int i;
|
||||
for ( i = 0; i < len; ++i )
|
||||
{
|
||||
output[i] = secrets_randomchar();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* This routine reads data from a binary file named ".secrets" and extracts the AES encryption key
|
||||
* and the AES Init Vector.
|
||||
* If the path parameter is not null the custom path is interpreted as a folder
|
||||
* containing the .secrets file. Otherwise the default location is used.
|
||||
* @return The keys structure or NULL on error
|
||||
*/
|
||||
static MAXKEYS *
|
||||
secrets_readKeys(char* path)
|
||||
{
|
||||
char secret_file[PATH_MAX+1];
|
||||
char *home;
|
||||
MAXKEYS *keys;
|
||||
struct stat secret_stats;
|
||||
int fd;
|
||||
int len;
|
||||
static int reported = 0;
|
||||
if(path != NULL)
|
||||
snprintf(secret_file, PATH_MAX, "%s/.secrets", path);
|
||||
else
|
||||
snprintf(secret_file, PATH_MAX, "%s/.secrets", get_datadir());
|
||||
/* Try to access secrets file */
|
||||
if (access(secret_file, R_OK) == -1)
|
||||
{
|
||||
int eno = errno;
|
||||
errno = 0;
|
||||
if (eno == ENOENT)
|
||||
{
|
||||
if (!reported)
|
||||
{
|
||||
char errbuf[STRERROR_BUFLEN];
|
||||
LOGIF(LM, (skygw_log_write(
|
||||
LOGFILE_MESSAGE,
|
||||
"Encrypted password file %s can't be accessed "
|
||||
"(%s). Password encryption is not used.",
|
||||
secret_file,
|
||||
strerror_r(eno, errbuf, sizeof(errbuf)))));
|
||||
reported = 1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
char errbuf[STRERROR_BUFLEN];
|
||||
LOGIF(LE, (skygw_log_write_flush(
|
||||
LOGFILE_ERROR,
|
||||
"Error : access for secrets file "
|
||||
"[%s] failed. Error %d, %s.",
|
||||
secret_file,
|
||||
eno,
|
||||
strerror_r(eno, errbuf, sizeof(errbuf)))));
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* open secret file */
|
||||
if ((fd = open(secret_file, O_RDONLY)) < 0)
|
||||
{
|
||||
int eno = errno;
|
||||
errno = 0;
|
||||
char errbuf[STRERROR_BUFLEN];
|
||||
LOGIF(LE, (skygw_log_write_flush(
|
||||
LOGFILE_ERROR,
|
||||
"Error : Failed opening secret "
|
||||
"file [%s]. Error %d, %s.",
|
||||
secret_file,
|
||||
eno,
|
||||
strerror_r(eno, errbuf, sizeof(errbuf)))));
|
||||
return NULL;
|
||||
|
||||
}
|
||||
|
||||
/* accessing file details */
|
||||
if (fstat(fd, &secret_stats) < 0) {
|
||||
int eno = errno;
|
||||
errno = 0;
|
||||
close(fd);
|
||||
char errbuf[STRERROR_BUFLEN];
|
||||
LOGIF(LE, (skygw_log_write_flush(
|
||||
LOGFILE_ERROR,
|
||||
"Error : fstat for secret file %s "
|
||||
"failed. Error %d, %s.",
|
||||
secret_file,
|
||||
eno,
|
||||
strerror_r(eno, errbuf, sizeof(errbuf)))));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (secret_stats.st_size != sizeof(MAXKEYS))
|
||||
{
|
||||
int eno = errno;
|
||||
errno = 0;
|
||||
close(fd);
|
||||
char errbuf[STRERROR_BUFLEN];
|
||||
LOGIF(LE, (skygw_log_write_flush(
|
||||
LOGFILE_ERROR,
|
||||
"Error : Secrets file %s has "
|
||||
"incorrect size. Error %d, %s.",
|
||||
secret_file,
|
||||
eno,
|
||||
strerror_r(eno, errbuf, sizeof(errbuf)))));
|
||||
return NULL;
|
||||
}
|
||||
if (secret_stats.st_mode != (S_IRUSR|S_IFREG))
|
||||
{
|
||||
close(fd);
|
||||
LOGIF(LE, (skygw_log_write_flush(
|
||||
LOGFILE_ERROR,
|
||||
"Error : Ignoring secrets file "
|
||||
"%s, invalid permissions.",
|
||||
secret_file)));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if ((keys = (MAXKEYS *)malloc(sizeof(MAXKEYS))) == NULL)
|
||||
{
|
||||
close(fd);
|
||||
LOGIF(LE, (skygw_log_write_flush(
|
||||
LOGFILE_ERROR,
|
||||
"Error : Memory allocation failed "
|
||||
"for key structure.")));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Read all data from file.
|
||||
* MAXKEYS (secrets.h) is struct for key, _not_ length-related macro.
|
||||
*/
|
||||
len = read(fd, keys, sizeof(MAXKEYS));
|
||||
|
||||
if (len != sizeof(MAXKEYS))
|
||||
{
|
||||
int eno = errno;
|
||||
errno = 0;
|
||||
close(fd);
|
||||
free(keys);
|
||||
char errbuf[STRERROR_BUFLEN];
|
||||
LOGIF(LE, (skygw_log_write_flush(
|
||||
LOGFILE_ERROR,
|
||||
"Error : Read from secrets file "
|
||||
"%s failed. Read %d, expected %d bytes. Error %d, %s.",
|
||||
secret_file,
|
||||
len,
|
||||
sizeof(MAXKEYS),
|
||||
eno,
|
||||
strerror_r(eno, errbuf, sizeof(errbuf)))));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Close the file */
|
||||
if (close(fd) < 0) {
|
||||
int eno = errno;
|
||||
errno = 0;
|
||||
free(keys);
|
||||
char errbuf[STRERROR_BUFLEN];
|
||||
LOGIF(LE, (skygw_log_write_flush(
|
||||
LOGFILE_ERROR,
|
||||
"Error : Failed closing the "
|
||||
"secrets file %s. Error %d, %s.",
|
||||
secret_file,
|
||||
eno,
|
||||
strerror_r(eno, errbuf, sizeof(errbuf)))));
|
||||
return NULL;
|
||||
}
|
||||
ss_dassert(keys != NULL);
|
||||
return keys;
|
||||
}
|
||||
|
||||
/**
|
||||
* secrets_writeKeys
|
||||
*
|
||||
* This routine writes into a binary file the AES encryption key
|
||||
* and the AES Init Vector
|
||||
*
|
||||
* @param secret_file The file with secret keys
|
||||
* @return 0 on success and 1 on failure
|
||||
*/
|
||||
int secrets_writeKeys(char *path)
|
||||
{
|
||||
int fd,randfd;
|
||||
unsigned int randval;
|
||||
MAXKEYS key;
|
||||
char secret_file[PATH_MAX + 10];
|
||||
|
||||
if(strlen(path) > PATH_MAX)
|
||||
{
|
||||
skygw_log_write(LOGFILE_ERROR,"Error: Pathname too long.");
|
||||
return 1;
|
||||
}
|
||||
|
||||
snprintf(secret_file,PATH_MAX + 9,"%s/.secrets",path);
|
||||
secret_file[PATH_MAX + 9] = '\0';
|
||||
|
||||
/* Open for writing | Create | Truncate the file for writing */
|
||||
if ((fd = open(secret_file, O_CREAT | O_WRONLY | O_TRUNC, S_IRUSR)) < 0)
|
||||
{
|
||||
char errbuf[STRERROR_BUFLEN];
|
||||
LOGIF(LE, (skygw_log_write_flush(
|
||||
LOGFILE_ERROR,
|
||||
"Error : failed opening secret "
|
||||
"file [%s]. Error %d, %s.",
|
||||
secret_file,
|
||||
errno,
|
||||
strerror_r(errno, errbuf, sizeof(errbuf)))));
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Open for writing | Create | Truncate the file for writing */
|
||||
if ((randfd = open("/dev/random", O_RDONLY)) < 0)
|
||||
{
|
||||
char errbuf[STRERROR_BUFLEN];
|
||||
LOGIF(LE, (skygw_log_write_flush(
|
||||
LOGFILE_ERROR,
|
||||
"Error : failed opening /dev/random. Error %d, %s.",
|
||||
errno,
|
||||
strerror_r(errno, errbuf, sizeof(errbuf)))));
|
||||
close(fd);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if(read(randfd,(void*)&randval,sizeof(unsigned int)) < 1)
|
||||
{
|
||||
LOGIF(LE, (skygw_log_write_flush(
|
||||
LOGFILE_ERROR,
|
||||
"Error : failed to read /dev/random.")));
|
||||
close(fd);
|
||||
close(randfd);
|
||||
return 1;
|
||||
}
|
||||
|
||||
close(randfd);
|
||||
secrets_random_str(key.enckey, MAXSCALE_KEYLEN);
|
||||
secrets_random_str(key.initvector, MAXSCALE_IV_LEN);
|
||||
|
||||
/* Write data */
|
||||
if (write(fd, &key, sizeof(key)) < 0)
|
||||
{
|
||||
char errbuf[STRERROR_BUFLEN];
|
||||
LOGIF(LE, (skygw_log_write_flush(
|
||||
LOGFILE_ERROR,
|
||||
"Error : failed writing into "
|
||||
"secret file [%s]. Error %d, %s.",
|
||||
secret_file,
|
||||
errno,
|
||||
strerror_r(errno, errbuf, sizeof(errbuf)))));
|
||||
close(fd);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* close file */
|
||||
if (close(fd) < 0)
|
||||
{
|
||||
char errbuf[STRERROR_BUFLEN];
|
||||
LOGIF(LE, (skygw_log_write_flush(
|
||||
LOGFILE_ERROR,
|
||||
"Error : failed closing the "
|
||||
"secret file [%s]. Error %d, %s.",
|
||||
secret_file,
|
||||
errno,
|
||||
strerror_r(errno, errbuf, sizeof(errbuf)))));
|
||||
}
|
||||
|
||||
if( chmod(secret_file, S_IRUSR) < 0)
|
||||
{
|
||||
char errbuf[STRERROR_BUFLEN];
|
||||
LOGIF(LE, (skygw_log_write_flush(
|
||||
LOGFILE_ERROR,
|
||||
"Error : failed to change the permissions of the"
|
||||
"secret file [%s]. Error %d, %s.",
|
||||
secret_file,
|
||||
errno,
|
||||
strerror_r(errno, errbuf, sizeof(errbuf)))));
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Decrypt a password that is stored inthe MaxScale configuration file.
|
||||
* If the password is not encrypted, ie is not a HEX string, then the
|
||||
* original is returned, this allows for backward compatibility with
|
||||
* unencrypted password.
|
||||
*
|
||||
* Note the return is always a malloc'd string that the caller must free
|
||||
*
|
||||
* @param crypt The encrypted password
|
||||
* @return The decrypted password
|
||||
*/
|
||||
char *
|
||||
decryptPassword(char *crypt)
|
||||
{
|
||||
MAXKEYS *keys;
|
||||
AES_KEY aeskey;
|
||||
unsigned char *plain;
|
||||
char *ptr;
|
||||
unsigned char encrypted[80];
|
||||
int enlen;
|
||||
|
||||
keys = secrets_readKeys(NULL);
|
||||
if (!keys)
|
||||
return strdup(crypt);
|
||||
/*
|
||||
** If the input is not a HEX string return the input
|
||||
** it probably was not encrypted
|
||||
*/
|
||||
for (ptr = crypt; *ptr; ptr++)
|
||||
{
|
||||
if (!isxdigit(*ptr))
|
||||
{
|
||||
free(keys);
|
||||
return strdup(crypt);
|
||||
}
|
||||
}
|
||||
|
||||
enlen = strlen(crypt) / 2;
|
||||
gw_hex2bin(encrypted, crypt, strlen(crypt));
|
||||
|
||||
if ((plain = (unsigned char *)malloc(80)) == NULL)
|
||||
{
|
||||
free(keys);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
AES_set_decrypt_key(keys->enckey, 8 * MAXSCALE_KEYLEN, &aeskey);
|
||||
|
||||
AES_cbc_encrypt(encrypted, plain, enlen, &aeskey, keys->initvector, AES_DECRYPT);
|
||||
free(keys);
|
||||
|
||||
return (char *)plain;
|
||||
}
|
||||
|
||||
/**
|
||||
* Encrypt a password that can be stored in the MaxScale configuration file.
|
||||
*
|
||||
* Note the return is always a malloc'd string that the caller must free
|
||||
* @param path Path the the .secrets file
|
||||
* @param password The password to encrypt
|
||||
* @return The encrypted password
|
||||
*/
|
||||
char *
|
||||
encryptPassword(char* path, char *password)
|
||||
{
|
||||
MAXKEYS *keys;
|
||||
AES_KEY aeskey;
|
||||
int padded_len;
|
||||
char *hex_output;
|
||||
unsigned char padded_passwd[80];
|
||||
unsigned char encrypted[80];
|
||||
|
||||
if ((keys = secrets_readKeys(path)) == NULL)
|
||||
return NULL;
|
||||
|
||||
memset(padded_passwd, 0, 80);
|
||||
strncpy((char *)padded_passwd, password, 79);
|
||||
padded_len = ((strlen(password) / AES_BLOCK_SIZE) + 1) * AES_BLOCK_SIZE;
|
||||
|
||||
AES_set_encrypt_key(keys->enckey, 8 * MAXSCALE_KEYLEN, &aeskey);
|
||||
|
||||
AES_cbc_encrypt(padded_passwd, encrypted, padded_len, &aeskey, keys->initvector, AES_ENCRYPT);
|
||||
hex_output = (char *)malloc(padded_len * 2);
|
||||
gw_bin2hex(hex_output, encrypted, padded_len);
|
||||
free(keys);
|
||||
|
||||
return hex_output;
|
||||
}
|
||||
/*
|
||||
* 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
|
||||
*/
|
||||
|
||||
#include <secrets.h>
|
||||
#include <time.h>
|
||||
#include <skygw_utils.h>
|
||||
#include <log_manager.h>
|
||||
#include <ctype.h>
|
||||
#include <mysql_client_server_protocol.h>
|
||||
#include <gwdirs.h>
|
||||
#include <random_jkiss.h>
|
||||
|
||||
/**
|
||||
* Generate a random printable character
|
||||
*
|
||||
* @return A random printable character
|
||||
*/
|
||||
static unsigned char
|
||||
secrets_randomchar()
|
||||
{
|
||||
return(char) ((random_jkiss() % ('~' - ' ')) + ' ');
|
||||
}
|
||||
|
||||
static int
|
||||
secrets_random_str(unsigned char *output, int len)
|
||||
{
|
||||
for (int i = 0; i < len; ++i)
|
||||
{
|
||||
output[i] = secrets_randomchar();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* This routine reads data from a binary file named ".secrets" and extracts the AES encryption key
|
||||
* and the AES Init Vector.
|
||||
* If the path parameter is not null the custom path is interpreted as a folder
|
||||
* containing the .secrets file. Otherwise the default location is used.
|
||||
* @return The keys structure or NULL on error
|
||||
*/
|
||||
static MAXKEYS *
|
||||
secrets_readKeys(const char* path)
|
||||
{
|
||||
char secret_file[PATH_MAX + 1];
|
||||
char *home;
|
||||
MAXKEYS *keys;
|
||||
struct stat secret_stats;
|
||||
int fd;
|
||||
int len;
|
||||
static int reported = 0;
|
||||
|
||||
if (path != NULL)
|
||||
{
|
||||
snprintf(secret_file, PATH_MAX, "%s/.secrets", path);
|
||||
}
|
||||
else
|
||||
{
|
||||
snprintf(secret_file, PATH_MAX, "%s/.secrets", get_datadir());
|
||||
}
|
||||
/* Try to access secrets file */
|
||||
if (access(secret_file, R_OK) == -1)
|
||||
{
|
||||
int eno = errno;
|
||||
errno = 0;
|
||||
if (eno == ENOENT)
|
||||
{
|
||||
if (!reported)
|
||||
{
|
||||
char errbuf[STRERROR_BUFLEN];
|
||||
LOGIF(LM, (skygw_log_write(LOGFILE_MESSAGE,
|
||||
"Encrypted password file %s can't be accessed "
|
||||
"(%s). Password encryption is not used.",
|
||||
secret_file,
|
||||
strerror_r(eno, errbuf, sizeof(errbuf)))));
|
||||
reported = 1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
char errbuf[STRERROR_BUFLEN];
|
||||
LOGIF(LE, (skygw_log_write_flush(LOGFILE_ERROR,
|
||||
"Error : access for secrets file "
|
||||
"[%s] failed. Error %d, %s.",
|
||||
secret_file,
|
||||
eno,
|
||||
strerror_r(eno, errbuf, sizeof(errbuf)))));
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* open secret file */
|
||||
if ((fd = open(secret_file, O_RDONLY)) < 0)
|
||||
{
|
||||
int eno = errno;
|
||||
errno = 0;
|
||||
char errbuf[STRERROR_BUFLEN];
|
||||
LOGIF(LE, (skygw_log_write_flush(LOGFILE_ERROR,
|
||||
"Error : Failed opening secret "
|
||||
"file [%s]. Error %d, %s.",
|
||||
secret_file,
|
||||
eno,
|
||||
strerror_r(eno, errbuf, sizeof(errbuf)))));
|
||||
return NULL;
|
||||
|
||||
}
|
||||
|
||||
/* accessing file details */
|
||||
if (fstat(fd, &secret_stats) < 0)
|
||||
{
|
||||
int eno = errno;
|
||||
errno = 0;
|
||||
close(fd);
|
||||
char errbuf[STRERROR_BUFLEN];
|
||||
LOGIF(LE, (skygw_log_write_flush(LOGFILE_ERROR,
|
||||
"Error : fstat for secret file %s "
|
||||
"failed. Error %d, %s.",
|
||||
secret_file,
|
||||
eno,
|
||||
strerror_r(eno, errbuf, sizeof(errbuf)))));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (secret_stats.st_size != sizeof(MAXKEYS))
|
||||
{
|
||||
int eno = errno;
|
||||
errno = 0;
|
||||
close(fd);
|
||||
char errbuf[STRERROR_BUFLEN];
|
||||
LOGIF(LE, (skygw_log_write_flush(LOGFILE_ERROR,
|
||||
"Error : Secrets file %s has "
|
||||
"incorrect size. Error %d, %s.",
|
||||
secret_file,
|
||||
eno,
|
||||
strerror_r(eno, errbuf, sizeof(errbuf)))));
|
||||
return NULL;
|
||||
}
|
||||
if (secret_stats.st_mode != (S_IRUSR | S_IFREG))
|
||||
{
|
||||
close(fd);
|
||||
LOGIF(LE, (skygw_log_write_flush(LOGFILE_ERROR,
|
||||
"Error : Ignoring secrets file "
|
||||
"%s, invalid permissions.",
|
||||
secret_file)));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if ((keys = (MAXKEYS *) malloc(sizeof(MAXKEYS))) == NULL)
|
||||
{
|
||||
close(fd);
|
||||
LOGIF(LE, (skygw_log_write_flush(LOGFILE_ERROR,
|
||||
"Error : Memory allocation failed "
|
||||
"for key structure.")));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Read all data from file.
|
||||
* MAXKEYS (secrets.h) is struct for key, _not_ length-related macro.
|
||||
*/
|
||||
len = read(fd, keys, sizeof(MAXKEYS));
|
||||
|
||||
if (len != sizeof(MAXKEYS))
|
||||
{
|
||||
int eno = errno;
|
||||
errno = 0;
|
||||
close(fd);
|
||||
free(keys);
|
||||
char errbuf[STRERROR_BUFLEN];
|
||||
LOGIF(LE, (skygw_log_write_flush(LOGFILE_ERROR,
|
||||
"Error : Read from secrets file "
|
||||
"%s failed. Read %d, expected %d bytes. Error %d, %s.",
|
||||
secret_file,
|
||||
len,
|
||||
sizeof(MAXKEYS),
|
||||
eno,
|
||||
strerror_r(eno, errbuf, sizeof(errbuf)))));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Close the file */
|
||||
if (close(fd) < 0)
|
||||
{
|
||||
int eno = errno;
|
||||
errno = 0;
|
||||
free(keys);
|
||||
char errbuf[STRERROR_BUFLEN];
|
||||
LOGIF(LE, (skygw_log_write_flush(LOGFILE_ERROR,
|
||||
"Error : Failed closing the "
|
||||
"secrets file %s. Error %d, %s.",
|
||||
secret_file,
|
||||
eno,
|
||||
strerror_r(eno, errbuf, sizeof(errbuf)))));
|
||||
return NULL;
|
||||
}
|
||||
ss_dassert(keys != NULL);
|
||||
return keys;
|
||||
}
|
||||
|
||||
/**
|
||||
* secrets_writeKeys
|
||||
*
|
||||
* This routine writes into a binary file the AES encryption key
|
||||
* and the AES Init Vector
|
||||
*
|
||||
* @param secret_file The file with secret keys
|
||||
* @return 0 on success and 1 on failure
|
||||
*/
|
||||
int secrets_writeKeys(const char *path)
|
||||
{
|
||||
int fd, randfd;
|
||||
unsigned int randval;
|
||||
MAXKEYS key;
|
||||
char secret_file[PATH_MAX + 10];
|
||||
|
||||
if (strlen(path) > PATH_MAX)
|
||||
{
|
||||
skygw_log_write(LOGFILE_ERROR, "Error: Pathname too long.");
|
||||
return 1;
|
||||
}
|
||||
|
||||
snprintf(secret_file, PATH_MAX + 9, "%s/.secrets", path);
|
||||
secret_file[PATH_MAX + 9] = '\0';
|
||||
|
||||
/* Open for writing | Create | Truncate the file for writing */
|
||||
if ((fd = open(secret_file, O_CREAT | O_WRONLY | O_TRUNC, S_IRUSR)) < 0)
|
||||
{
|
||||
char errbuf[STRERROR_BUFLEN];
|
||||
LOGIF(LE, (skygw_log_write_flush(LOGFILE_ERROR,
|
||||
"Error : failed opening secret "
|
||||
"file [%s]. Error %d, %s.",
|
||||
secret_file,
|
||||
errno,
|
||||
strerror_r(errno, errbuf, sizeof(errbuf)))));
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Open for writing | Create | Truncate the file for writing */
|
||||
if ((randfd = open("/dev/random", O_RDONLY)) < 0)
|
||||
{
|
||||
char errbuf[STRERROR_BUFLEN];
|
||||
LOGIF(LE, (skygw_log_write_flush(LOGFILE_ERROR,
|
||||
"Error : failed opening /dev/random. Error %d, %s.",
|
||||
errno,
|
||||
strerror_r(errno, errbuf, sizeof(errbuf)))));
|
||||
close(fd);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (read(randfd, (void*) &randval, sizeof(unsigned int)) < 1)
|
||||
{
|
||||
LOGIF(LE, (skygw_log_write_flush(LOGFILE_ERROR,
|
||||
"Error : failed to read /dev/random.")));
|
||||
close(fd);
|
||||
close(randfd);
|
||||
return 1;
|
||||
}
|
||||
|
||||
close(randfd);
|
||||
secrets_random_str(key.enckey, MAXSCALE_KEYLEN);
|
||||
secrets_random_str(key.initvector, MAXSCALE_IV_LEN);
|
||||
|
||||
/* Write data */
|
||||
if (write(fd, &key, sizeof(key)) < 0)
|
||||
{
|
||||
char errbuf[STRERROR_BUFLEN];
|
||||
LOGIF(LE, (skygw_log_write_flush(LOGFILE_ERROR,
|
||||
"Error : failed writing into "
|
||||
"secret file [%s]. Error %d, %s.",
|
||||
secret_file,
|
||||
errno,
|
||||
strerror_r(errno, errbuf, sizeof(errbuf)))));
|
||||
close(fd);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* close file */
|
||||
if (close(fd) < 0)
|
||||
{
|
||||
char errbuf[STRERROR_BUFLEN];
|
||||
LOGIF(LE, (skygw_log_write_flush(LOGFILE_ERROR,
|
||||
"Error : failed closing the "
|
||||
"secret file [%s]. Error %d, %s.",
|
||||
secret_file,
|
||||
errno,
|
||||
strerror_r(errno, errbuf, sizeof(errbuf)))));
|
||||
}
|
||||
|
||||
if (chmod(secret_file, S_IRUSR) < 0)
|
||||
{
|
||||
char errbuf[STRERROR_BUFLEN];
|
||||
LOGIF(LE, (skygw_log_write_flush(LOGFILE_ERROR,
|
||||
"Error : failed to change the permissions of the"
|
||||
"secret file [%s]. Error %d, %s.",
|
||||
secret_file,
|
||||
errno,
|
||||
strerror_r(errno, errbuf, sizeof(errbuf)))));
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Decrypt a password that is stored inthe MaxScale configuration file.
|
||||
* If the password is not encrypted, ie is not a HEX string, then the
|
||||
* original is returned, this allows for backward compatibility with
|
||||
* unencrypted password.
|
||||
*
|
||||
* Note the return is always a malloc'd string that the caller must free
|
||||
*
|
||||
* @param crypt The encrypted password
|
||||
* @return The decrypted password
|
||||
*/
|
||||
char *
|
||||
decryptPassword(const char *crypt)
|
||||
{
|
||||
MAXKEYS *keys;
|
||||
AES_KEY aeskey;
|
||||
unsigned char *plain;
|
||||
char *ptr;
|
||||
unsigned char encrypted[80];
|
||||
int enlen;
|
||||
|
||||
keys = secrets_readKeys(NULL);
|
||||
if (!keys)
|
||||
{
|
||||
return strdup(crypt);
|
||||
}
|
||||
/*
|
||||
** If the input is not a HEX string return the input
|
||||
** it probably was not encrypted
|
||||
*/
|
||||
for (ptr = crypt; *ptr; ptr++)
|
||||
{
|
||||
if (!isxdigit(*ptr))
|
||||
{
|
||||
free(keys);
|
||||
return strdup(crypt);
|
||||
}
|
||||
}
|
||||
|
||||
enlen = strlen(crypt) / 2;
|
||||
gw_hex2bin(encrypted, crypt, strlen(crypt));
|
||||
|
||||
if ((plain = (unsigned char *) malloc(80)) == NULL)
|
||||
{
|
||||
free(keys);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
AES_set_decrypt_key(keys->enckey, 8 * MAXSCALE_KEYLEN, &aeskey);
|
||||
|
||||
AES_cbc_encrypt(encrypted, plain, enlen, &aeskey, keys->initvector, AES_DECRYPT);
|
||||
free(keys);
|
||||
|
||||
return(char *) plain;
|
||||
}
|
||||
|
||||
/**
|
||||
* Encrypt a password that can be stored in the MaxScale configuration file.
|
||||
*
|
||||
* Note the return is always a malloc'd string that the caller must free
|
||||
* @param path Path the the .secrets file
|
||||
* @param password The password to encrypt
|
||||
* @return The encrypted password
|
||||
*/
|
||||
char *
|
||||
encryptPassword(const char* path, const char *password)
|
||||
{
|
||||
MAXKEYS *keys;
|
||||
AES_KEY aeskey;
|
||||
int padded_len;
|
||||
char *hex_output;
|
||||
unsigned char padded_passwd[80];
|
||||
unsigned char encrypted[80];
|
||||
|
||||
if ((keys = secrets_readKeys(path)) == NULL)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
memset(padded_passwd, 0, 80);
|
||||
strncpy((char *) padded_passwd, password, 79);
|
||||
padded_len = ((strlen(password) / AES_BLOCK_SIZE) + 1) * AES_BLOCK_SIZE;
|
||||
|
||||
AES_set_encrypt_key(keys->enckey, 8 * MAXSCALE_KEYLEN, &aeskey);
|
||||
|
||||
AES_cbc_encrypt(padded_passwd, encrypted, padded_len, &aeskey, keys->initvector, AES_ENCRYPT);
|
||||
hex_output = (char *) malloc(padded_len * 2);
|
||||
gw_bin2hex(hex_output, encrypted, padded_len);
|
||||
free(keys);
|
||||
|
||||
return hex_output;
|
||||
}
|
||||
|
@ -74,7 +74,7 @@ SERVER *server;
|
||||
server->server_chk_top = CHK_NUM_SERVER;
|
||||
server->server_chk_tail = CHK_NUM_SERVER;
|
||||
#endif
|
||||
server->name = strdup(servname);
|
||||
server->name = strndup(servname, MAX_SERVER_NAME_LEN);
|
||||
server->protocol = strdup(protocol);
|
||||
server->port = port;
|
||||
server->status = SERVER_RUNNING;
|
||||
@ -82,6 +82,7 @@ SERVER *server;
|
||||
server->rlag = -2;
|
||||
server->master_id = -1;
|
||||
server->depth = -1;
|
||||
spinlock_init(&server->lock);
|
||||
server->persistent = NULL;
|
||||
server->persistmax = 0;
|
||||
spinlock_init(&server->persistlock);
|
||||
@ -666,6 +667,7 @@ char *status = NULL;
|
||||
void
|
||||
server_set_status(SERVER *server, int bit)
|
||||
{
|
||||
spinlock_acquire(&server->lock);
|
||||
server->status |= bit;
|
||||
|
||||
/** clear error logged flag before the next failure */
|
||||
@ -673,6 +675,7 @@ server_set_status(SERVER *server, int bit)
|
||||
{
|
||||
server->master_err_is_logged = false;
|
||||
}
|
||||
spinlock_release(&server->lock);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -684,7 +687,9 @@ server_set_status(SERVER *server, int bit)
|
||||
void
|
||||
server_clear_status(SERVER *server, int bit)
|
||||
{
|
||||
spinlock_acquire(&server->lock);
|
||||
server->status &= ~bit;
|
||||
spinlock_release(&server->lock);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -910,3 +915,54 @@ server_update_port(SERVER *server, unsigned short port)
|
||||
spinlock_release(&server_spin);
|
||||
}
|
||||
|
||||
static struct {
|
||||
char *str;
|
||||
unsigned int bit;
|
||||
} ServerBits[] = {
|
||||
{ "running", SERVER_RUNNING },
|
||||
{ "master", SERVER_MASTER },
|
||||
{ "slave", SERVER_SLAVE },
|
||||
{ "synced", SERVER_JOINED },
|
||||
{ "ndb", SERVER_NDB },
|
||||
{ "maintenance", SERVER_MAINT },
|
||||
{ "maint", SERVER_MAINT },
|
||||
{ NULL, 0 }
|
||||
};
|
||||
|
||||
/**
|
||||
* Map the server status bit
|
||||
*
|
||||
* @param str String representation
|
||||
* @return bit value or 0 on error
|
||||
*/
|
||||
unsigned int
|
||||
server_map_status(char *str)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; ServerBits[i].str; i++)
|
||||
if (!strcasecmp(str, ServerBits[i].str))
|
||||
return ServerBits[i].bit;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the version string of the server.
|
||||
* @param server Server to update
|
||||
* @param string Version string
|
||||
* @return True if the assignment of the version string was successful, false if
|
||||
* memory allocation failed.
|
||||
*/
|
||||
bool server_set_version_string(SERVER* server, const char* string)
|
||||
{
|
||||
bool rval = true;
|
||||
spinlock_acquire(&server->lock);
|
||||
free(server->server_string);
|
||||
if ((server->server_string = strdup(string)) == NULL)
|
||||
{
|
||||
MXS_ERROR("Memory allocation failed.");
|
||||
rval = false;
|
||||
}
|
||||
spinlock_release(&server->lock);
|
||||
return rval;
|
||||
}
|
||||
|
@ -348,6 +348,7 @@ GWPROTOCOL *funcs;
|
||||
users_free(service->users);
|
||||
service->users = NULL;
|
||||
dcb_close(port->listener);
|
||||
service->users = NULL;
|
||||
port->listener = NULL;
|
||||
LOGIF(LE, (skygw_log_write_flush(
|
||||
LOGFILE_ERROR,
|
||||
@ -384,6 +385,7 @@ GWPROTOCOL *funcs;
|
||||
service->users = NULL;
|
||||
dcb_close(port->listener);
|
||||
port->listener = NULL;
|
||||
service->users = NULL;
|
||||
goto retblock;
|
||||
}
|
||||
}
|
||||
|
@ -27,6 +27,13 @@
|
||||
* @endverbatim
|
||||
*/
|
||||
|
||||
// To ensure that ss_info_assert asserts also when builing in non-debug mode.
|
||||
#if !defined(SS_DEBUG)
|
||||
#define SS_DEBUG
|
||||
#endif
|
||||
#if defined(NDEBUG)
|
||||
#undef NDEBUG
|
||||
#endif
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
@ -27,6 +27,13 @@
|
||||
* @endverbatim
|
||||
*/
|
||||
|
||||
// To ensure that ss_info_assert asserts also when builing in non-debug mode.
|
||||
#if !defined(SS_DEBUG)
|
||||
#define SS_DEBUG
|
||||
#endif
|
||||
#if defined(NDEBUG)
|
||||
#undef NDEBUG
|
||||
#endif
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
@ -28,6 +28,13 @@
|
||||
* @endverbatim
|
||||
*/
|
||||
|
||||
// To ensure that ss_info_assert asserts also when builing in non-debug mode.
|
||||
#if !defined(SS_DEBUG)
|
||||
#define SS_DEBUG
|
||||
#endif
|
||||
#if defined(NDEBUG)
|
||||
#undef NDEBUG
|
||||
#endif
|
||||
#define FAILTEST(s) printf("TEST FAILED: " s "\n");return 1;
|
||||
#include <my_config.h>
|
||||
#include <mysql.h>
|
||||
|
@ -27,6 +27,13 @@
|
||||
* @endverbatim
|
||||
*/
|
||||
|
||||
// To ensure that ss_info_assert asserts also when builing in non-debug mode.
|
||||
#if !defined(SS_DEBUG)
|
||||
#define SS_DEBUG
|
||||
#endif
|
||||
#if defined(NDEBUG)
|
||||
#undef NDEBUG
|
||||
#endif
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
@ -27,6 +27,13 @@
|
||||
* @endverbatim
|
||||
*/
|
||||
|
||||
// To ensure that ss_info_assert asserts also when builing in non-debug mode.
|
||||
#if !defined(SS_DEBUG)
|
||||
#define SS_DEBUG
|
||||
#endif
|
||||
#if defined(NDEBUG)
|
||||
#undef NDEBUG
|
||||
#endif
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
@ -27,6 +27,13 @@
|
||||
* @endverbatim
|
||||
*/
|
||||
|
||||
// To ensure that ss_info_assert asserts also when builing in non-debug mode.
|
||||
#if !defined(SS_DEBUG)
|
||||
#define SS_DEBUG
|
||||
#endif
|
||||
#if defined(NDEBUG)
|
||||
#undef NDEBUG
|
||||
#endif
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
@ -154,7 +161,6 @@ static bool do_hashtest(
|
||||
|
||||
ss_dfprintf(stderr, "\t\t..done\n\nTest completed successfully.\n\n");
|
||||
|
||||
CHK_HASHTABLE(h);
|
||||
hashtable_free(h);
|
||||
|
||||
|
||||
|
@ -27,6 +27,13 @@
|
||||
* @endverbatim
|
||||
*/
|
||||
|
||||
// To ensure that ss_info_assert asserts also when builing in non-debug mode.
|
||||
#if !defined(SS_DEBUG)
|
||||
#define SS_DEBUG
|
||||
#endif
|
||||
#if defined(NDEBUG)
|
||||
#undef NDEBUG
|
||||
#endif
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
@ -37,7 +44,7 @@
|
||||
* test1 Allocate table of users and mess around with it
|
||||
*
|
||||
*/
|
||||
void skygw_log_sync_all(void);
|
||||
int mxs_log_flush_sync(void);
|
||||
static int
|
||||
test1()
|
||||
{
|
||||
@ -49,13 +56,13 @@ HINT *hint;
|
||||
char* name = strdup("name");
|
||||
hint = hint_create_parameter(NULL, name, "value");
|
||||
free(name);
|
||||
skygw_log_sync_all();
|
||||
mxs_log_flush_sync();
|
||||
ss_info_dassert(NULL != hint, "New hint list should not be null");
|
||||
ss_info_dassert(0 == strcmp("value", hint->value), "Hint value should be correct");
|
||||
ss_info_dassert(0 != hint_exists(&hint, HINT_PARAMETER), "Hint of parameter type should exist");
|
||||
ss_dfprintf(stderr, "\t..done\nFree hints.");
|
||||
if (NULL != hint) hint_free(hint);
|
||||
skygw_log_sync_all();
|
||||
mxs_log_flush_sync();
|
||||
ss_dfprintf(stderr, "\t..done\n");
|
||||
|
||||
return 0;
|
||||
|
@ -27,6 +27,13 @@
|
||||
* @endverbatim
|
||||
*/
|
||||
|
||||
// To ensure that ss_info_assert asserts also when builing in non-debug mode.
|
||||
#if !defined(SS_DEBUG)
|
||||
#define SS_DEBUG
|
||||
#endif
|
||||
#if defined(NDEBUG)
|
||||
#undef NDEBUG
|
||||
#endif
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
|
@ -27,6 +27,13 @@
|
||||
* @endverbatim
|
||||
*/
|
||||
|
||||
// To ensure that ss_info_assert asserts also when builing in non-debug mode.
|
||||
#if !defined(SS_DEBUG)
|
||||
#define SS_DEBUG
|
||||
#endif
|
||||
#if defined(NDEBUG)
|
||||
#undef NDEBUG
|
||||
#endif
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
@ -27,6 +27,13 @@
|
||||
* @endverbatim
|
||||
*/
|
||||
|
||||
// To ensure that ss_info_assert asserts also when builing in non-debug mode.
|
||||
#if !defined(SS_DEBUG)
|
||||
#define SS_DEBUG
|
||||
#endif
|
||||
#if defined(NDEBUG)
|
||||
#undef NDEBUG
|
||||
#endif
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
@ -27,6 +27,13 @@
|
||||
* @endverbatim
|
||||
*/
|
||||
|
||||
// To ensure that ss_info_assert asserts also when builing in non-debug mode.
|
||||
#if !defined(SS_DEBUG)
|
||||
#define SS_DEBUG
|
||||
#endif
|
||||
#if defined(NDEBUG)
|
||||
#undef NDEBUG
|
||||
#endif
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
@ -48,7 +55,7 @@ char *status;
|
||||
ss_dfprintf(stderr,
|
||||
"testserver : creating server called MyServer");
|
||||
server = server_alloc("MyServer", "HTTPD", 9876);
|
||||
skygw_log_sync_all();
|
||||
mxs_log_flush_sync();
|
||||
|
||||
//ss_info_dassert(NULL != service, "New server with valid protocol and port must not be null");
|
||||
//ss_info_dassert(0 != service_isvalid(service), "Service must be valid after creation");
|
||||
@ -56,32 +63,32 @@ char *status;
|
||||
ss_dfprintf(stderr, "\t..done\nTest Parameter for Server.");
|
||||
ss_info_dassert(NULL == serverGetParameter(server, "name"), "Parameter should be null when not set");
|
||||
serverAddParameter(server, "name", "value");
|
||||
skygw_log_sync_all();
|
||||
mxs_log_flush_sync();
|
||||
ss_info_dassert(0 == strcmp("value", serverGetParameter(server, "name")), "Parameter should be returned correctly");
|
||||
ss_dfprintf(stderr, "\t..done\nTesting Unique Name for Server.");
|
||||
ss_info_dassert(NULL == server_find_by_unique_name("uniquename"), "Should not find non-existent unique name.");
|
||||
server_set_unique_name(server, "uniquename");
|
||||
skygw_log_sync_all();
|
||||
mxs_log_flush_sync();
|
||||
ss_info_dassert(server == server_find_by_unique_name("uniquename"), "Should find by unique name.");
|
||||
ss_dfprintf(stderr, "\t..done\nTesting Status Setting for Server.");
|
||||
status = server_status(server);
|
||||
skygw_log_sync_all();
|
||||
mxs_log_flush_sync();
|
||||
ss_info_dassert(0 == strcmp("Running", status), "Status of Server should be Running by default.");
|
||||
if (NULL != status) free(status);
|
||||
server_set_status(server, SERVER_MASTER);
|
||||
status = server_status(server);
|
||||
skygw_log_sync_all();
|
||||
mxs_log_flush_sync();
|
||||
ss_info_dassert(0 == strcmp("Master, Running", status), "Should find correct status.");
|
||||
server_clear_status(server, SERVER_MASTER);
|
||||
free(status);
|
||||
status = server_status(server);
|
||||
skygw_log_sync_all();
|
||||
mxs_log_flush_sync();
|
||||
ss_info_dassert(0 == strcmp("Running", status), "Status of Server should be Running after master status cleared.");
|
||||
if (NULL != status) free(status);
|
||||
ss_dfprintf(stderr, "\t..done\nRun Prints for Server and all Servers.");
|
||||
printServer(server);
|
||||
printAllServers();
|
||||
skygw_log_sync_all();
|
||||
mxs_log_flush_sync();
|
||||
ss_dfprintf(stderr, "\t..done\nFreeing Server.");
|
||||
ss_info_dassert(0 != server_free(server), "Free should succeed");
|
||||
ss_dfprintf(stderr, "\t..done\n");
|
||||
|
@ -60,12 +60,12 @@ init_test_env(NULL);
|
||||
ss_dfprintf(stderr,
|
||||
"testservice : creating service called MyService with router nonexistent");
|
||||
service = service_alloc("MyService", "non-existent");
|
||||
skygw_log_sync_all();
|
||||
mxs_log_flush_sync();
|
||||
ss_info_dassert(NULL == service, "New service with invalid router should be null");
|
||||
ss_info_dassert(0 == service_isvalid(service), "Service must not be valid after incorrect creation");
|
||||
ss_dfprintf(stderr, "\t..done\nValid service creation, router testroute.");
|
||||
service = service_alloc("MyService", "testroute");
|
||||
skygw_log_sync_all();
|
||||
mxs_log_flush_sync();
|
||||
ss_info_dassert(NULL != service, "New service with valid router must not be null");
|
||||
ss_info_dassert(0 != service_isvalid(service), "Service must be valid after creation");
|
||||
ss_info_dassert(0 == strcmp("MyService", service_get_name(service)), "Service must have given name");
|
||||
@ -73,16 +73,16 @@ init_test_env(NULL);
|
||||
ss_info_dassert(0 != serviceAddProtocol(service, "testprotocol", "localhost", 9876), "Add Protocol should succeed");
|
||||
ss_info_dassert(0 != serviceHasProtocol(service, "testprotocol", 9876), "Service should have new protocol as requested");
|
||||
serviceStartProtocol(service, "testprotocol", 9876);
|
||||
skygw_log_sync_all();
|
||||
mxs_log_flush_sync();
|
||||
ss_dfprintf(stderr, "\t..done\nStarting Service.");
|
||||
result = serviceStart(service);
|
||||
skygw_log_sync_all();
|
||||
mxs_log_flush_sync();
|
||||
ss_info_dassert(0 != result, "Start should succeed");
|
||||
serviceStop(service);
|
||||
skygw_log_sync_all();
|
||||
mxs_log_flush_sync();
|
||||
ss_info_dassert(service->state == SERVICE_STATE_STOPPED, "Stop should succeed");
|
||||
result = serviceStartAll();
|
||||
skygw_log_sync_all();
|
||||
mxs_log_flush_sync();
|
||||
ss_info_dassert(0 != result, "Start all should succeed");
|
||||
ss_dfprintf(stderr, "\t..done\nStopping Service.");
|
||||
serviceStop(service);
|
||||
|
@ -27,6 +27,13 @@
|
||||
* @endverbatim
|
||||
*/
|
||||
|
||||
// To ensure that ss_info_assert asserts also when builing in non-debug mode.
|
||||
#if !defined(SS_DEBUG)
|
||||
#define SS_DEBUG
|
||||
#endif
|
||||
#if defined(NDEBUG)
|
||||
#undef NDEBUG
|
||||
#endif
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
@ -27,6 +27,13 @@
|
||||
* @endverbatim
|
||||
*/
|
||||
|
||||
// To ensure that ss_info_assert asserts also when builing in non-debug mode.
|
||||
#if !defined(SS_DEBUG)
|
||||
#define SS_DEBUG
|
||||
#endif
|
||||
#if defined(NDEBUG)
|
||||
#undef NDEBUG
|
||||
#endif
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
@ -58,39 +58,39 @@ int result, count;
|
||||
ss_dfprintf(stderr,
|
||||
"testusers : Initialise the user table.");
|
||||
users = users_alloc();
|
||||
skygw_log_sync_all();
|
||||
mxs_log_flush_sync();
|
||||
ss_info_dassert(NULL != users, "Allocating user table should not return NULL.")
|
||||
ss_dfprintf(stderr, "\t..done\nAdd a user");
|
||||
count = users_add(users, "username", "authorisation");
|
||||
skygw_log_sync_all();
|
||||
mxs_log_flush_sync();
|
||||
ss_info_dassert(1 == count, "Should add one user");
|
||||
authdata = users_fetch(users, "username");
|
||||
skygw_log_sync_all();
|
||||
mxs_log_flush_sync();
|
||||
ss_info_dassert(NULL != authdata, "Fetch valid user must not return NULL");
|
||||
ss_info_dassert(0 == strcmp("authorisation", authdata), "User authorisation should be correct");
|
||||
ss_dfprintf(stderr, "\t..done\nPrint users");
|
||||
usersPrint(users);
|
||||
skygw_log_sync_all();
|
||||
mxs_log_flush_sync();
|
||||
ss_dfprintf(stderr, "\t..done\nUpdate a user");
|
||||
count = users_update(users, "username", "newauth");
|
||||
skygw_log_sync_all();
|
||||
mxs_log_flush_sync();
|
||||
ss_info_dassert(1 == count, "Should update just one user");
|
||||
authdata = users_fetch(users, "username");
|
||||
skygw_log_sync_all();
|
||||
mxs_log_flush_sync();
|
||||
ss_info_dassert(NULL != authdata, "Fetch valid user must not return NULL");
|
||||
ss_info_dassert(0 == strcmp("newauth", authdata), "User authorisation should be correctly updated");
|
||||
|
||||
ss_dfprintf(stderr, "\t..done\nAdd another user");
|
||||
count = users_add(users, "username2", "authorisation2");
|
||||
skygw_log_sync_all();
|
||||
mxs_log_flush_sync();
|
||||
ss_info_dassert(1 == count, "Should add one user");
|
||||
ss_dfprintf(stderr, "\t..done\nDelete a user.");
|
||||
count = users_delete(users, "username");
|
||||
skygw_log_sync_all();
|
||||
mxs_log_flush_sync();
|
||||
ss_info_dassert(1 == count, "Should delete just one user");
|
||||
ss_dfprintf(stderr, "\t..done\nFree user table.");
|
||||
users_free(users);
|
||||
skygw_log_sync_all();
|
||||
mxs_log_flush_sync();
|
||||
ss_dfprintf(stderr, "\t..done\n");
|
||||
|
||||
return 0;
|
||||
|
@ -6,15 +6,21 @@
|
||||
#include <errno.h>
|
||||
#include <skygw_utils.h>
|
||||
#include <log_manager.h>
|
||||
#include <maxscale_pcre2.h>
|
||||
|
||||
#define MAXSCALE_EXTCMD_ARG_MAX 256
|
||||
|
||||
typedef struct extern_cmd_t{
|
||||
char* parameters[MAXSCALE_EXTCMD_ARG_MAX]; /*< Command arguments */
|
||||
char** argv; /*< Argument vector for the command, first being the actual command
|
||||
* being executed. */
|
||||
int n_exec; /*< Number of times executed */
|
||||
pid_t child; /*< PID of the child process */
|
||||
}EXTERNCMD;
|
||||
|
||||
char* externcmd_extract_command(const char* argstr);
|
||||
EXTERNCMD* externcmd_allocate(char* argstr);
|
||||
void externcmd_free(EXTERNCMD* cmd);
|
||||
int externcmd_execute(EXTERNCMD* cmd);
|
||||
bool externcmd_substitute_arg(EXTERNCMD* cmd, const char* re, const char* replace);
|
||||
bool externcmd_can_execute(const char* argstr);
|
||||
#endif
|
||||
|
@ -85,6 +85,7 @@ typedef struct hashtable {
|
||||
int n_readers; /**< Number of clients reading the table */
|
||||
int writelock; /**< The table is locked by a writer */
|
||||
bool ht_isflat; /**< Indicates whether hashtable is in stack or heap */
|
||||
int n_elements; /*< Number of added elements */
|
||||
#if defined(SS_DEBUG)
|
||||
skygw_chk_t ht_chk_tail;
|
||||
#endif
|
||||
@ -130,4 +131,5 @@ extern HASHITERATOR *hashtable_iterator(HASHTABLE *);
|
||||
extern void *hashtable_next(HASHITERATOR *);
|
||||
/**< Return the key of the hash table iterator */
|
||||
extern void hashtable_iterator_free(HASHITERATOR *);
|
||||
extern int hashtable_size(HASHTABLE *table);
|
||||
#endif
|
||||
|
@ -120,6 +120,7 @@ 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);
|
||||
void free_config_parameter(CONFIG_PARAMETER* p1);
|
||||
extern int config_truth_value(char *);
|
||||
extern double config_percentage_value(char *str);
|
||||
bool config_set_qualified_param(
|
||||
|
@ -21,6 +21,7 @@
|
||||
#include <server.h>
|
||||
#include <dcb.h>
|
||||
#include <resultset.h>
|
||||
#include <maxconfig.h>
|
||||
|
||||
/**
|
||||
* @file monitor.h The interface to the monitor module
|
||||
@ -140,6 +141,7 @@ typedef struct monitor {
|
||||
char* user; /*< Monitor username */
|
||||
char* password; /*< Monitor password */
|
||||
SPINLOCK lock;
|
||||
CONFIG_PARAMETER* parameters; /*< configuration parameters */
|
||||
MONITOR_SERVERS* databases; /*< List of databases the monitor monitors */
|
||||
monitor_state_t state; /**< The state of the monitor */
|
||||
int connect_timeout; /**< Connect timeout in seconds for mysql_real_connect */
|
||||
@ -160,9 +162,11 @@ extern void monitor_free(MONITOR *);
|
||||
extern MONITOR *monitor_find(char *);
|
||||
extern void monitorAddServer(MONITOR *, SERVER *);
|
||||
extern void monitorAddUser(MONITOR *, char *, char *);
|
||||
extern void monitorAddParameters(MONITOR *monitor, CONFIG_PARAMETER *params);
|
||||
extern void monitorStop(MONITOR *);
|
||||
extern void monitorStart(MONITOR *, void*);
|
||||
extern void monitorStopAll();
|
||||
extern void monitorStartAll();
|
||||
extern void monitorShowAll(DCB *);
|
||||
extern void monitorShow(DCB *, MONITOR *);
|
||||
extern void monitorList(DCB *);
|
||||
@ -170,4 +174,5 @@ extern void monitorSetInterval (MONITOR *, unsigned long);
|
||||
extern void monitorSetNetworkTimeout(MONITOR *, int, int);
|
||||
extern RESULTSET *monitorGetList();
|
||||
bool check_monitor_permissions(MONITOR* monitor);
|
||||
|
||||
#endif
|
||||
|
@ -24,8 +24,8 @@
|
||||
* @verbatim
|
||||
* Revision History
|
||||
*
|
||||
* Date Who Description
|
||||
* 23/06/2013 Massimiliano Pinto Initial implementation
|
||||
* Date Who Description
|
||||
* 23/06/2013 Massimiliano Pinto Initial implementation
|
||||
*
|
||||
* @endverbatim
|
||||
*/
|
||||
@ -40,18 +40,19 @@
|
||||
|
||||
#include <openssl/aes.h>
|
||||
|
||||
#define MAXSCALE_KEYLEN 32
|
||||
#define MAXSCALE_IV_LEN 16
|
||||
#define MAXSCALE_KEYLEN 32
|
||||
#define MAXSCALE_IV_LEN 16
|
||||
|
||||
/**
|
||||
* The key structure held in the secrets file
|
||||
*/
|
||||
typedef struct maxkeys {
|
||||
unsigned char enckey[MAXSCALE_KEYLEN];
|
||||
unsigned char initvector[MAXSCALE_IV_LEN];
|
||||
typedef struct maxkeys
|
||||
{
|
||||
unsigned char enckey[MAXSCALE_KEYLEN];
|
||||
unsigned char initvector[MAXSCALE_IV_LEN];
|
||||
} MAXKEYS;
|
||||
|
||||
extern int secrets_writeKeys(char *filename);
|
||||
extern char *decryptPassword(char *);
|
||||
extern char *encryptPassword(char*,char *);
|
||||
extern int secrets_writeKeys(const char *filename);
|
||||
extern char *decryptPassword(const char *);
|
||||
extern char *encryptPassword(const char*, const char *);
|
||||
#endif
|
||||
|
@ -49,6 +49,8 @@
|
||||
* @endverbatim
|
||||
*/
|
||||
|
||||
#define MAX_SERVER_NAME_LEN 1024
|
||||
|
||||
/**
|
||||
* The server parameters used for weighting routing decissions
|
||||
*
|
||||
@ -81,6 +83,7 @@ typedef struct server {
|
||||
#if defined(SS_DEBUG)
|
||||
skygw_chk_t server_chk_top;
|
||||
#endif
|
||||
SPINLOCK lock; /**< Common access lock */
|
||||
char *unique_name; /**< Unique name for the server */
|
||||
char *name; /**< Server name/IP address*/
|
||||
unsigned short port; /**< Port to listen on */
|
||||
@ -208,4 +211,6 @@ extern DCB *server_get_persistent(SERVER *, char *, const char *);
|
||||
extern void server_update_address(SERVER *, char *);
|
||||
extern void server_update_port(SERVER *, unsigned short);
|
||||
extern RESULTSET *serverGetList();
|
||||
extern unsigned int server_map_status(char *str);
|
||||
extern bool server_set_version_string(SERVER* server, const char* string);
|
||||
#endif
|
||||
|
@ -12,15 +12,7 @@ void init_test_env(char *path)
|
||||
|
||||
const char* logdir = path ? path : TEST_LOG_DIR;
|
||||
|
||||
char* argv[] =
|
||||
{
|
||||
"log_manager",
|
||||
"-l",
|
||||
"LOGFILE_ERROR",
|
||||
NULL
|
||||
};
|
||||
|
||||
skygw_logmanager_init(logdir, argc, argv);
|
||||
mxs_log_init(NULL, logdir, LOG_TARGET_DEFAULT);
|
||||
poll_init();
|
||||
hkinit();
|
||||
}
|
||||
|
@ -2213,7 +2213,7 @@ int main(int argc, char** argv)
|
||||
NULL
|
||||
};
|
||||
|
||||
skygw_logmanager_init(argc_,argv_);
|
||||
mxs_log_init(argc_,argv_);
|
||||
|
||||
|
||||
init_test_env(home);
|
||||
@ -2231,7 +2231,7 @@ int main(int argc, char** argv)
|
||||
printf("Failed to parse rule. Read the error log for the reason of the failure.\n");
|
||||
}
|
||||
|
||||
skygw_log_sync_all();
|
||||
mxs_log_flush_sync();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -15,10 +15,9 @@ int harness_init(int argc, char** argv, HARNESS_INSTANCE** inst){
|
||||
DCB* dcb;
|
||||
char cwd[1024];
|
||||
char tmp[2048];
|
||||
char** optstr;
|
||||
|
||||
if(!(argc == 2 && strcmp(argv[1],"-h") == 0)){
|
||||
skygw_logmanager_init(NULL,0,NULL);
|
||||
mxs_log_init(NULL,NULL,LOG_TARGET_DEFAULT);
|
||||
}
|
||||
|
||||
if(!(instance.head = calloc(1,sizeof(FILTERCHAIN))))
|
||||
@ -52,11 +51,7 @@ int harness_init(int argc, char** argv, HARNESS_INSTANCE** inst){
|
||||
getcwd(cwd,sizeof(cwd));
|
||||
sprintf(tmp,"%s",cwd);
|
||||
|
||||
optstr = (char**)malloc(sizeof(char*)*2);
|
||||
optstr[0] = strdup("log_manager");
|
||||
optstr[1] = NULL;
|
||||
skygw_logmanager_init(tmp, 1, optstr);
|
||||
free(optstr);
|
||||
mxs_log_init(NULL, tmp, LOG_TARGET_DEFAULT);
|
||||
|
||||
rval = process_opts(argc,argv);
|
||||
|
||||
|
@ -11,8 +11,7 @@ int main(int argc, char** argv){
|
||||
if(harness_init(argc,argv,&hinstance)){
|
||||
printf("Error: Initialization failed.\n");
|
||||
skygw_log_write(LOGFILE_ERROR,"Error: Initialization failed.\n");
|
||||
skygw_logmanager_done();
|
||||
skygw_logmanager_exit();
|
||||
mxs_log_finish();
|
||||
return 1;
|
||||
}
|
||||
|
||||
@ -230,8 +229,7 @@ int main(int argc, char** argv){
|
||||
|
||||
free_buffers();
|
||||
free_filters();
|
||||
skygw_logmanager_done();
|
||||
skygw_logmanager_exit();
|
||||
mxs_log_finish();
|
||||
free(instance.head);
|
||||
|
||||
return 0;
|
||||
|
@ -35,8 +35,7 @@ int main(int argc,char** argv)
|
||||
if(harness_init(argc,argv,&inst) || inst->error){
|
||||
printf("Error: Initialization failed.\n");
|
||||
skygw_log_write(LOGFILE_ERROR,"Error: Initialization failed.\n");
|
||||
skygw_logmanager_done();
|
||||
skygw_logmanager_exit();
|
||||
mxs_log_finish();
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
@ -73,7 +73,12 @@ typedef enum
|
||||
MAXOP_LITERAL,
|
||||
MAXOP_PREDICATE,
|
||||
MAXOP_LIKE,
|
||||
MAXOP_EQUAL
|
||||
MAXOP_EQUAL,
|
||||
MAXOP_FLUSH,
|
||||
MAXOP_SET,
|
||||
MAXOP_CLEAR,
|
||||
MAXOP_SHUTDOWN,
|
||||
MAXOP_RESTART
|
||||
} MAXINFO_OPERATOR;
|
||||
|
||||
/**
|
||||
@ -109,6 +114,11 @@ typedef struct maxinfo_tree {
|
||||
#define LT_FROM 7
|
||||
#define LT_STAR 8
|
||||
#define LT_VARIABLE 9
|
||||
#define LT_FLUSH 10
|
||||
#define LT_SET 11
|
||||
#define LT_CLEAR 12
|
||||
#define LT_SHUTDOWN 13
|
||||
#define LT_RESTART 14
|
||||
|
||||
|
||||
/**
|
||||
|
@ -154,32 +154,15 @@ startMonitor(void *arg,void* opt)
|
||||
handle->use_priority = config_truth_value(params->value);
|
||||
else if(!strcmp(params->name,"script"))
|
||||
{
|
||||
if(handle->script)
|
||||
{
|
||||
free(handle->script);
|
||||
handle->script = NULL;
|
||||
}
|
||||
|
||||
if(access(params->value,X_OK) == 0)
|
||||
{
|
||||
handle->script = strdup(params->value);
|
||||
}
|
||||
else
|
||||
{
|
||||
script_error = true;
|
||||
if(access(params->value,F_OK) == 0)
|
||||
{
|
||||
skygw_log_write(LE,
|
||||
"Error: The file cannot be executed: %s",
|
||||
params->value);
|
||||
}
|
||||
else
|
||||
{
|
||||
skygw_log_write(LE,
|
||||
"Error: The file cannot be found: %s",
|
||||
params->value);
|
||||
}
|
||||
}
|
||||
if (externcmd_can_execute(params->value))
|
||||
{
|
||||
free(handle->script);
|
||||
handle->script = strdup(params->value);
|
||||
}
|
||||
else
|
||||
{
|
||||
script_error = true;
|
||||
}
|
||||
}
|
||||
else if(!strcmp(params->name,"events"))
|
||||
{
|
||||
@ -327,11 +310,10 @@ char *server_string;
|
||||
|
||||
/* get server version string */
|
||||
server_string = (char *)mysql_get_server_info(database->con);
|
||||
if (server_string) {
|
||||
database->server->server_string = realloc(database->server->server_string, strlen(server_string)+1);
|
||||
if (database->server->server_string)
|
||||
strcpy(database->server->server_string, server_string);
|
||||
}
|
||||
if (server_string)
|
||||
{
|
||||
server_set_version_string(database->server, server_string);
|
||||
}
|
||||
|
||||
/* Check if the the Galera FSM shows this node is joined to the cluster */
|
||||
if (mysql_query(database->con, "SHOW STATUS LIKE 'wsrep_local_state'") == 0
|
||||
|
@ -136,31 +136,15 @@ startMonitor(void *arg,void* opt)
|
||||
}
|
||||
else if(!strcmp(params->name,"script"))
|
||||
{
|
||||
if(handle->script)
|
||||
{
|
||||
free(handle->script);
|
||||
}
|
||||
if(access(params->value,X_OK) == 0)
|
||||
{
|
||||
handle->script = strdup(params->value);
|
||||
}
|
||||
else
|
||||
{
|
||||
script_error = true;
|
||||
if(access(params->value,F_OK) == 0)
|
||||
{
|
||||
skygw_log_write(LE,
|
||||
"Error: The file cannot be executed: %s",
|
||||
params->value);
|
||||
}
|
||||
else
|
||||
{
|
||||
skygw_log_write(LE,
|
||||
"Error: The file cannot be found: %s",
|
||||
params->value);
|
||||
}
|
||||
handle->script = NULL;
|
||||
}
|
||||
if (externcmd_can_execute(params->value))
|
||||
{
|
||||
free(handle->script);
|
||||
handle->script = strdup(params->value);
|
||||
}
|
||||
else
|
||||
{
|
||||
script_error = true;
|
||||
}
|
||||
}
|
||||
else if(!strcmp(params->name,"events"))
|
||||
{
|
||||
@ -312,11 +296,10 @@ char *server_string;
|
||||
|
||||
/* get server version string */
|
||||
server_string = (char *)mysql_get_server_info(database->con);
|
||||
if (server_string) {
|
||||
database->server->server_string = realloc(database->server->server_string, strlen(server_string)+1);
|
||||
if (database->server->server_string)
|
||||
strcpy(database->server->server_string, server_string);
|
||||
}
|
||||
if (server_string)
|
||||
{
|
||||
server_set_version_string(database->server, server_string);
|
||||
}
|
||||
|
||||
/* get server_id form current node */
|
||||
if (mysql_query(database->con, "SELECT @@server_id") == 0
|
||||
|
@ -17,6 +17,7 @@
|
||||
*/
|
||||
|
||||
#include <monitor_common.h>
|
||||
#include <maxscale_pcre2.h>
|
||||
|
||||
monitor_event_t mon_name_to_event(char* tok);
|
||||
|
||||
@ -225,23 +226,32 @@ case NEW_DONOR_EVENT:
|
||||
|
||||
}
|
||||
|
||||
void mon_append_node_names(MONITOR_SERVERS* start,char* str, int len)
|
||||
/**
|
||||
* Create a list of running servers
|
||||
* @param start Monitored servers
|
||||
* @param dest Destination where the string is formed
|
||||
* @param len Length of @c dest
|
||||
*/
|
||||
void mon_append_node_names(MONITOR_SERVERS* start, char* dest, int len)
|
||||
{
|
||||
MONITOR_SERVERS* ptr = start;
|
||||
bool first = true;
|
||||
int slen = strlen(str);
|
||||
char arr[256];
|
||||
while(ptr && slen < len)
|
||||
int slen = strlen(dest);
|
||||
char arr[MAX_SERVER_NAME_LEN + 32]; // Some extra space for port
|
||||
while (ptr && slen < len)
|
||||
{
|
||||
if(!first)
|
||||
{
|
||||
strncat(str,",",len);
|
||||
}
|
||||
first = false;
|
||||
sprintf(arr,"%s:%d",ptr->server->name,ptr->server->port);
|
||||
strncat(str,arr,len);
|
||||
ptr = ptr->next;
|
||||
slen = strlen(str);
|
||||
if(SERVER_IS_RUNNING(ptr->server))
|
||||
{
|
||||
if (!first)
|
||||
{
|
||||
strncat(dest, ",", len);
|
||||
}
|
||||
first = false;
|
||||
snprintf(arr, sizeof(arr), "%s:%d", ptr->server->name, ptr->server->port);
|
||||
strncat(dest, arr, len);
|
||||
slen = strlen(dest);
|
||||
}
|
||||
ptr = ptr->next;
|
||||
}
|
||||
}
|
||||
|
||||
@ -302,23 +312,26 @@ bool mon_print_fail_status(
|
||||
*/
|
||||
void monitor_launch_script(MONITOR* mon, MONITOR_SERVERS* ptr, char* script)
|
||||
{
|
||||
char argstr[PATH_MAX + MON_ARG_MAX + 1];
|
||||
EXTERNCMD* cmd;
|
||||
char nodelist[PATH_MAX + MON_ARG_MAX + 1] = {'\0'};
|
||||
char event[strlen(mon_get_event_name(ptr))];
|
||||
char initiator[strlen(ptr->server->name) + 24]; // Extra space for port
|
||||
|
||||
snprintf(argstr, PATH_MAX + MON_ARG_MAX,
|
||||
"%s --event=%s --initiator=%s:%d --nodelist=",
|
||||
script,
|
||||
mon_get_event_name(ptr),
|
||||
ptr->server->name,
|
||||
ptr->server->port);
|
||||
snprintf(initiator, sizeof(initiator), "%s:%d", ptr->server->name, ptr->server->port);
|
||||
snprintf(event, sizeof(event), "%s", mon_get_event_name(ptr));
|
||||
mon_append_node_names(mon->databases, nodelist, PATH_MAX + MON_ARG_MAX);
|
||||
|
||||
mon_append_node_names(mon->databases, argstr, PATH_MAX + MON_ARG_MAX);
|
||||
if ((cmd = externcmd_allocate(argstr)) == NULL)
|
||||
EXTERNCMD* cmd = externcmd_allocate(script);
|
||||
|
||||
if (cmd == NULL)
|
||||
{
|
||||
skygw_log_write(LE, "Failed to initialize script: %s", script);
|
||||
return;
|
||||
}
|
||||
|
||||
externcmd_substitute_arg(cmd, "[$]INITIATOR", initiator);
|
||||
externcmd_substitute_arg(cmd, "[$]EVENT", event);
|
||||
externcmd_substitute_arg(cmd, "[$]NODELIST", nodelist);
|
||||
|
||||
if (externcmd_execute(cmd))
|
||||
{
|
||||
skygw_log_write(LOGFILE_ERROR,
|
||||
|
@ -168,32 +168,18 @@ startMonitor(void *arg, void* opt)
|
||||
handle->detectStaleMaster = config_truth_value(params->value);
|
||||
else if(!strcmp(params->name,"detect_replication_lag"))
|
||||
handle->replicationHeartbeat = config_truth_value(params->value);
|
||||
else if(!strcmp(params->name,"script"))
|
||||
{
|
||||
if(handle->script)
|
||||
free(handle->script);
|
||||
if(access(params->value,X_OK) == 0)
|
||||
{
|
||||
handle->script = strdup(params->value);
|
||||
}
|
||||
else
|
||||
{
|
||||
script_error = true;
|
||||
if(access(params->value,F_OK) == 0)
|
||||
{
|
||||
skygw_log_write(LE,
|
||||
"Error: The file cannot be executed: %s",
|
||||
params->value);
|
||||
}
|
||||
else
|
||||
{
|
||||
skygw_log_write(LE,
|
||||
"Error: The file cannot be found: %s",
|
||||
params->value);
|
||||
}
|
||||
handle->script = NULL;
|
||||
}
|
||||
}
|
||||
else if (!strcmp(params->name, "script"))
|
||||
{
|
||||
if (externcmd_can_execute(params->value))
|
||||
{
|
||||
free(handle->script);
|
||||
handle->script = strdup(params->value);
|
||||
}
|
||||
else
|
||||
{
|
||||
script_error = true;
|
||||
}
|
||||
}
|
||||
else if(!strcmp(params->name,"events"))
|
||||
{
|
||||
if(mon_parse_event_string((bool*)&handle->events,sizeof(handle->events),params->value) != 0)
|
||||
@ -659,10 +645,9 @@ monitorDatabase(MONITOR *mon, MONITOR_SERVERS *database)
|
||||
|
||||
/* get server version string */
|
||||
server_string = (char *)mysql_get_server_info(database->con);
|
||||
if (server_string) {
|
||||
database->server->server_string = realloc(database->server->server_string, strlen(server_string)+1);
|
||||
if (database->server->server_string)
|
||||
strcpy(database->server->server_string, server_string);
|
||||
if (server_string)
|
||||
{
|
||||
server_set_version_string(database->server, server_string);
|
||||
}
|
||||
|
||||
/* get server_id form current node */
|
||||
|
@ -127,29 +127,15 @@ startMonitor(void *arg,void* opt)
|
||||
{
|
||||
if(!strcmp(params->name,"script"))
|
||||
{
|
||||
if(handle->script)
|
||||
free(handle->script);
|
||||
if(access(params->value,X_OK) == 0)
|
||||
{
|
||||
handle->script = strdup(params->value);
|
||||
}
|
||||
else
|
||||
{
|
||||
script_error = true;
|
||||
if(access(params->value,F_OK) == 0)
|
||||
{
|
||||
skygw_log_write(LE,
|
||||
"Error: The file cannot be executed: %s",
|
||||
params->value);
|
||||
}
|
||||
else
|
||||
{
|
||||
skygw_log_write(LE,
|
||||
"Error: The file cannot be found: %s",
|
||||
params->value);
|
||||
}
|
||||
handle->script = NULL;
|
||||
}
|
||||
if (externcmd_can_execute(params->value))
|
||||
{
|
||||
free(handle->script);
|
||||
handle->script = strdup(params->value);
|
||||
}
|
||||
else
|
||||
{
|
||||
script_error = true;
|
||||
}
|
||||
}
|
||||
else if(!strcmp(params->name,"events"))
|
||||
{
|
||||
@ -277,11 +263,10 @@ char *server_string;
|
||||
|
||||
/* get server version string */
|
||||
server_string = (char *)mysql_get_server_info(database->con);
|
||||
if (server_string) {
|
||||
database->server->server_string = realloc(database->server->server_string, strlen(server_string)+1);
|
||||
if (database->server->server_string)
|
||||
strcpy(database->server->server_string, server_string);
|
||||
}
|
||||
if (server_string)
|
||||
{
|
||||
server_set_version_string(database->server, server_string);
|
||||
}
|
||||
|
||||
/* Check if the the SQL node is able to contact one or more data nodes */
|
||||
if (mysql_query(database->con, "SHOW STATUS LIKE 'Ndb_number_of_ready_data_nodes'") == 0
|
||||
|
@ -580,6 +580,7 @@ char task_name[BLRM_TASK_NAME_LEN+1] = "";
|
||||
inst->service->name)));
|
||||
if (service->users) {
|
||||
users_free(service->users);
|
||||
service->users = NULL;
|
||||
}
|
||||
|
||||
free(inst);
|
||||
@ -658,6 +659,7 @@ char task_name[BLRM_TASK_NAME_LEN+1] = "";
|
||||
|
||||
if (service->users) {
|
||||
users_free(service->users);
|
||||
service->users = NULL;
|
||||
}
|
||||
|
||||
if (service->dbref && service->dbref->server) {
|
||||
|
@ -86,8 +86,6 @@ return 1;
|
||||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
char** arg_vector;
|
||||
int arg_count = 1;
|
||||
ROUTER_INSTANCE *inst;
|
||||
int fd;
|
||||
int ret;
|
||||
@ -126,21 +124,9 @@ int main(int argc, char **argv) {
|
||||
|
||||
num_args = optind;
|
||||
|
||||
arg_vector = malloc(sizeof(char*)*(arg_count + 1));
|
||||
mxs_log_init(NULL, NULL, LOG_TARGET_DEFAULT);
|
||||
|
||||
if(arg_vector == NULL)
|
||||
{
|
||||
fprintf(stderr,"Error: Memory allocation failed for log manager arg_vector.\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
arg_vector[0] = "logmanager";
|
||||
arg_vector[1] = NULL;
|
||||
skygw_logmanager_init(NULL, arg_count, arg_vector);
|
||||
|
||||
skygw_log_set_augmentation(0);
|
||||
|
||||
free(arg_vector);
|
||||
mxs_log_set_augmentation(0);
|
||||
|
||||
if (!debug_out)
|
||||
skygw_log_disable(LOGFILE_DEBUG);
|
||||
@ -151,8 +137,8 @@ int main(int argc, char **argv) {
|
||||
LOGIF(LE, (skygw_log_write_flush(LOGFILE_ERROR,
|
||||
"Error: Memory allocation failed for ROUTER_INSTANCE")));
|
||||
|
||||
skygw_log_sync_all();
|
||||
skygw_logmanager_done();
|
||||
mxs_log_flush_sync();
|
||||
mxs_log_finish();
|
||||
|
||||
return 1;
|
||||
}
|
||||
@ -175,8 +161,8 @@ int main(int argc, char **argv) {
|
||||
"Failed to open binlog file %s: %s",
|
||||
path, strerror(errno))));
|
||||
|
||||
skygw_log_sync_all();
|
||||
skygw_logmanager_done();
|
||||
mxs_log_flush_sync();
|
||||
mxs_log_finish();
|
||||
|
||||
free(inst);
|
||||
|
||||
@ -208,13 +194,13 @@ int main(int argc, char **argv) {
|
||||
|
||||
close(inst->binlog_fd);
|
||||
|
||||
skygw_log_sync_all();
|
||||
mxs_log_flush_sync();
|
||||
|
||||
LOGIF(LM, (skygw_log_write_flush(LOGFILE_MESSAGE,
|
||||
"Check retcode: %i, Binlog Pos = %llu", ret, inst->binlog_position)));
|
||||
|
||||
skygw_log_sync_all();
|
||||
skygw_logmanager_done();
|
||||
mxs_log_flush_sync();
|
||||
mxs_log_finish();
|
||||
|
||||
free(inst);
|
||||
|
||||
|
@ -73,11 +73,9 @@ static struct option long_options[] = {
|
||||
};
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
char** arg_vector;
|
||||
ROUTER_INSTANCE *inst;
|
||||
int ret;
|
||||
int rc;
|
||||
int arg_count = 1;
|
||||
char error_string[BINLOG_ERROR_MSG_LEN + 1] = "";
|
||||
CHANGE_MASTER_OPTIONS change_master;
|
||||
char query[255+1]="";
|
||||
@ -91,18 +89,7 @@ int main(int argc, char **argv) {
|
||||
|
||||
roptions = strdup("server-id=3,heartbeat=200,binlogdir=/not_exists/my_dir,transaction_safety=1,master_version=5.6.99-common,master_hostname=common_server,master_uuid=xxx-fff-cccc-fff,master-id=999");
|
||||
|
||||
arg_vector = malloc(sizeof(char*)*(arg_count + 1));
|
||||
|
||||
if(arg_vector == NULL)
|
||||
{
|
||||
fprintf(stderr,"Error: Memory allocation FAILED for log manager arg_vector.\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
arg_vector[0] = "logmanager";
|
||||
arg_vector[1] = NULL;
|
||||
skygw_logmanager_init(NULL, arg_count,arg_vector);
|
||||
free(arg_vector);
|
||||
mxs_log_init(NULL, NULL, LOG_TARGET_DEFAULT);
|
||||
|
||||
skygw_log_disable(LOGFILE_DEBUG);
|
||||
skygw_log_disable(LOGFILE_TRACE);
|
||||
@ -140,8 +127,8 @@ int main(int argc, char **argv) {
|
||||
LOGIF(LE, (skygw_log_write_flush(LOGFILE_ERROR,
|
||||
"Error: Memory allocation FAILED for ROUTER_INSTANCE")));
|
||||
|
||||
skygw_log_sync_all();
|
||||
skygw_logmanager_done();
|
||||
mxs_log_flush_sync();
|
||||
mxs_log_finish();
|
||||
|
||||
return 1;
|
||||
}
|
||||
@ -591,8 +578,8 @@ int main(int argc, char **argv) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
skygw_log_sync_all();
|
||||
skygw_logmanager_done();
|
||||
mxs_log_flush_sync();
|
||||
mxs_log_finish();
|
||||
|
||||
free(inst);
|
||||
|
||||
|
@ -621,29 +621,48 @@ struct subcommand removeoptions[] = {
|
||||
static void
|
||||
flushlog(DCB *pdcb, char *logname)
|
||||
{
|
||||
if (logname == NULL)
|
||||
bool unrecognized = false;
|
||||
bool deprecated = false;
|
||||
|
||||
if (!strcasecmp(logname, "error"))
|
||||
{
|
||||
}
|
||||
else if (!strcasecmp(logname, "error"))
|
||||
{
|
||||
skygw_log_rotate(LOGFILE_ERROR);
|
||||
deprecated = true;
|
||||
}
|
||||
else if (!strcasecmp(logname, "message"))
|
||||
{
|
||||
skygw_log_rotate(LOGFILE_MESSAGE);
|
||||
deprecated = true;
|
||||
}
|
||||
else if (!strcasecmp(logname, "trace"))
|
||||
{
|
||||
skygw_log_rotate(LOGFILE_TRACE);
|
||||
deprecated = true;
|
||||
}
|
||||
else if (!strcasecmp(logname, "debug"))
|
||||
{
|
||||
skygw_log_rotate(LOGFILE_DEBUG);
|
||||
deprecated = true;
|
||||
}
|
||||
else if (!strcasecmp(logname, "maxscale"))
|
||||
{
|
||||
; // nop
|
||||
}
|
||||
else
|
||||
{
|
||||
dcb_printf(pdcb, "Unexpected logfile name, expected "
|
||||
"error, message, trace or debug.\n");
|
||||
unrecognized = true;
|
||||
}
|
||||
|
||||
if (unrecognized)
|
||||
{
|
||||
dcb_printf(pdcb, "Unexpected logfile name '%s', expected: 'maxscale'.\n", logname);
|
||||
}
|
||||
else
|
||||
{
|
||||
mxs_log_rotate();
|
||||
|
||||
if (deprecated)
|
||||
{
|
||||
dcb_printf(pdcb,
|
||||
"'%s' is deprecated, currently there is only one log 'maxscale', "
|
||||
"which was rotated.\n", logname);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -655,10 +674,7 @@ flushlog(DCB *pdcb, char *logname)
|
||||
static void
|
||||
flushlogs(DCB *pdcb)
|
||||
{
|
||||
skygw_log_rotate(LOGFILE_ERROR);
|
||||
skygw_log_rotate(LOGFILE_MESSAGE);
|
||||
skygw_log_rotate(LOGFILE_TRACE);
|
||||
skygw_log_rotate(LOGFILE_DEBUG);
|
||||
mxs_log_rotate();
|
||||
}
|
||||
|
||||
|
||||
@ -678,8 +694,8 @@ struct subcommand flushoptions[] = {
|
||||
"logs",
|
||||
0,
|
||||
flushlogs,
|
||||
"Flush the content of all log files, close that logs, rename them and open a new log files",
|
||||
"Flush the content of all log files, close that logs, rename them and open a new log files",
|
||||
"Flush the content of all log files, close those logs, rename them and open a new log files",
|
||||
"Flush the content of all log files, close those logs, rename them and open a new log files",
|
||||
{0, 0, 0}
|
||||
},
|
||||
{
|
||||
@ -1100,40 +1116,6 @@ restart_service(DCB *dcb, SERVICE *service)
|
||||
serviceRestart(service);
|
||||
}
|
||||
|
||||
static struct {
|
||||
char *str;
|
||||
unsigned int bit;
|
||||
} ServerBits[] = {
|
||||
{ "running", SERVER_RUNNING },
|
||||
{ "master", SERVER_MASTER },
|
||||
{ "slave", SERVER_SLAVE },
|
||||
{ "synced", SERVER_JOINED },
|
||||
{ "ndb", SERVER_NDB },
|
||||
{ "maintenance", SERVER_MAINT },
|
||||
{ "maint", SERVER_MAINT },
|
||||
{ NULL, 0 }
|
||||
};
|
||||
/**
|
||||
* Map the server status bit
|
||||
*
|
||||
* @param str String representation
|
||||
* @return bit value or 0 on error
|
||||
*/
|
||||
static unsigned int
|
||||
server_map_status(char *str)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; ServerBits[i].str; i++)
|
||||
{
|
||||
if (!strcasecmp(str, ServerBits[i].str))
|
||||
{
|
||||
return ServerBits[i].bit;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the status bit of a server
|
||||
*
|
||||
@ -1603,7 +1585,7 @@ static void enable_log_priority(DCB *dcb, char *arg1)
|
||||
|
||||
if (priority != -1)
|
||||
{
|
||||
mxs_log_enable_priority(priority);
|
||||
mxs_log_set_priority_enabled(priority, true);
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -1621,7 +1603,7 @@ static void disable_log_priority(DCB *dcb, char *arg1)
|
||||
|
||||
if (priority != -1)
|
||||
{
|
||||
mxs_log_enable_priority(priority);
|
||||
mxs_log_set_priority_enabled(priority, false);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -780,7 +780,7 @@ maxinfo_add_mysql_user(SERVICE *service) {
|
||||
"maxinfo: create hex_sha1_sha1_password failed for service user %s",
|
||||
service_user)));
|
||||
users_free(service->users);
|
||||
|
||||
service->users = NULL;
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
@ -54,7 +54,12 @@ static void exec_select(DCB *dcb, MAXINFO_TREE *tree);
|
||||
static void exec_show_variables(DCB *dcb, MAXINFO_TREE *filter);
|
||||
static void exec_show_status(DCB *dcb, MAXINFO_TREE *filter);
|
||||
static int maxinfo_pattern_match(char *pattern, char *str);
|
||||
|
||||
static void exec_flush(DCB *dcb, MAXINFO_TREE *tree);
|
||||
static void exec_set(DCB *dcb, MAXINFO_TREE *tree);
|
||||
static void exec_clear(DCB *dcb, MAXINFO_TREE *tree);
|
||||
static void exec_shutdown(DCB *dcb, MAXINFO_TREE *tree);
|
||||
static void exec_restart(DCB *dcb, MAXINFO_TREE *tree);
|
||||
void maxinfo_send_ok(DCB *dcb);
|
||||
/**
|
||||
* Execute a parse tree and return the result set or runtime error
|
||||
*
|
||||
@ -72,6 +77,23 @@ maxinfo_execute(DCB *dcb, MAXINFO_TREE *tree)
|
||||
case MAXOP_SELECT:
|
||||
exec_select(dcb, tree);
|
||||
break;
|
||||
|
||||
case MAXOP_FLUSH:
|
||||
exec_flush(dcb, tree);
|
||||
break;
|
||||
case MAXOP_SET:
|
||||
exec_set(dcb, tree);
|
||||
break;
|
||||
case MAXOP_CLEAR:
|
||||
exec_clear(dcb, tree);
|
||||
break;
|
||||
case MAXOP_SHUTDOWN:
|
||||
exec_shutdown(dcb, tree);
|
||||
break;
|
||||
case MAXOP_RESTART:
|
||||
exec_restart(dcb, tree);
|
||||
break;
|
||||
|
||||
case MAXOP_TABLE:
|
||||
case MAXOP_COLUMNS:
|
||||
case MAXOP_LITERAL:
|
||||
@ -274,6 +296,448 @@ char errmsg[120];
|
||||
LOGIF(LM, (skygw_log_write(LOGFILE_MESSAGE, errmsg)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Flush all logs to disk and rotate them.
|
||||
* @param dcb The DCB that connects to the client
|
||||
* @param tree The parse tree for the query
|
||||
*/
|
||||
void exec_flush_logs(DCB *dcb, MAXINFO_TREE *tree)
|
||||
{
|
||||
mxs_log_rotate();
|
||||
maxinfo_send_ok(dcb);
|
||||
}
|
||||
|
||||
/**
|
||||
* The table of flush commands that are supported
|
||||
*/
|
||||
static struct
|
||||
{
|
||||
char *name;
|
||||
void (*func)(DCB *, MAXINFO_TREE *);
|
||||
} flush_commands[] = {
|
||||
{ "logs", exec_flush_logs},
|
||||
{ NULL, NULL}
|
||||
};
|
||||
|
||||
/**
|
||||
* Execute a flush command parse tree and return the result set or runtime error
|
||||
*
|
||||
* @param dcb The DCB that connects to the client
|
||||
* @param tree The parse tree for the query
|
||||
*/
|
||||
static void
|
||||
exec_flush(DCB *dcb, MAXINFO_TREE *tree)
|
||||
{
|
||||
int i;
|
||||
char errmsg[120];
|
||||
|
||||
for (i = 0; flush_commands[i].name; i++)
|
||||
{
|
||||
if (strcasecmp(flush_commands[i].name, tree->value) == 0)
|
||||
{
|
||||
(*flush_commands[i].func)(dcb, tree->right);
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (strlen(tree->value) > 80) // Prevent buffer overrun
|
||||
{
|
||||
tree->value[80] = 0;
|
||||
}
|
||||
sprintf(errmsg, "Unsupported flush command '%s'", tree->value);
|
||||
maxinfo_send_error(dcb, 0, errmsg);
|
||||
skygw_log_write(LE, errmsg);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the server status.
|
||||
* @param dcb Client DCB
|
||||
* @param tree Parse tree
|
||||
*/
|
||||
void exec_set_server(DCB *dcb, MAXINFO_TREE *tree)
|
||||
{
|
||||
SERVER* server = server_find_by_unique_name(tree->value);
|
||||
char errmsg[120];
|
||||
|
||||
if (server)
|
||||
{
|
||||
int status = server_map_status(tree->right->value);
|
||||
if (status != 0)
|
||||
{
|
||||
server_set_status(server, status);
|
||||
maxinfo_send_ok(dcb);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (strlen(tree->right->value) > 80) // Prevent buffer overrun
|
||||
{
|
||||
tree->right->value[80] = 0;
|
||||
}
|
||||
sprintf(errmsg, "Invalid argument '%s'", tree->right->value);
|
||||
maxinfo_send_error(dcb, 0, errmsg);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (strlen(tree->value) > 80) // Prevent buffer overrun
|
||||
{
|
||||
tree->value[80] = 0;
|
||||
}
|
||||
sprintf(errmsg, "Invalid argument '%s'", tree->value);
|
||||
maxinfo_send_error(dcb, 0, errmsg);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The table of set commands that are supported
|
||||
*/
|
||||
static struct
|
||||
{
|
||||
char *name;
|
||||
void (*func)(DCB *, MAXINFO_TREE *);
|
||||
} set_commands[] = {
|
||||
{ "server", exec_set_server},
|
||||
{ NULL, NULL}
|
||||
};
|
||||
|
||||
/**
|
||||
* Execute a set command parse tree and return the result set or runtime error
|
||||
*
|
||||
* @param dcb The DCB that connects to the client
|
||||
* @param tree The parse tree for the query
|
||||
*/
|
||||
static void
|
||||
exec_set(DCB *dcb, MAXINFO_TREE *tree)
|
||||
{
|
||||
int i;
|
||||
char errmsg[120];
|
||||
|
||||
for (i = 0; set_commands[i].name; i++)
|
||||
{
|
||||
if (strcasecmp(set_commands[i].name, tree->value) == 0)
|
||||
{
|
||||
(*set_commands[i].func)(dcb, tree->right);
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (strlen(tree->value) > 80) // Prevent buffer overrun
|
||||
{
|
||||
tree->value[80] = 0;
|
||||
}
|
||||
sprintf(errmsg, "Unsupported set command '%s'", tree->value);
|
||||
maxinfo_send_error(dcb, 0, errmsg);
|
||||
skygw_log_write(LE, errmsg);
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear the server status.
|
||||
* @param dcb Client DCB
|
||||
* @param tree Parse tree
|
||||
*/
|
||||
void exec_clear_server(DCB *dcb, MAXINFO_TREE *tree)
|
||||
{
|
||||
SERVER* server = server_find_by_unique_name(tree->value);
|
||||
char errmsg[120];
|
||||
|
||||
if (server)
|
||||
{
|
||||
int status = server_map_status(tree->right->value);
|
||||
if (status != 0)
|
||||
{
|
||||
server_clear_status(server, status);
|
||||
maxinfo_send_ok(dcb);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (strlen(tree->right->value) > 80) // Prevent buffer overrun
|
||||
{
|
||||
tree->right->value[80] = 0;
|
||||
}
|
||||
sprintf(errmsg, "Invalid argument '%s'", tree->right->value);
|
||||
maxinfo_send_error(dcb, 0, errmsg);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (strlen(tree->value) > 80) // Prevent buffer overrun
|
||||
{
|
||||
tree->value[80] = 0;
|
||||
}
|
||||
sprintf(errmsg, "Invalid argument '%s'", tree->value);
|
||||
maxinfo_send_error(dcb, 0, errmsg);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The table of clear commands that are supported
|
||||
*/
|
||||
static struct
|
||||
{
|
||||
char *name;
|
||||
void (*func)(DCB *, MAXINFO_TREE *);
|
||||
} clear_commands[] = {
|
||||
{ "server", exec_clear_server},
|
||||
{ NULL, NULL}
|
||||
};
|
||||
|
||||
/**
|
||||
* Execute a clear command parse tree and return the result set or runtime error
|
||||
*
|
||||
* @param dcb The DCB that connects to the client
|
||||
* @param tree The parse tree for the query
|
||||
*/
|
||||
static void
|
||||
exec_clear(DCB *dcb, MAXINFO_TREE *tree)
|
||||
{
|
||||
int i;
|
||||
char errmsg[120];
|
||||
|
||||
for (i = 0; clear_commands[i].name; i++)
|
||||
{
|
||||
if (strcasecmp(clear_commands[i].name, tree->value) == 0)
|
||||
{
|
||||
(*clear_commands[i].func)(dcb, tree->right);
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (strlen(tree->value) > 80) // Prevent buffer overrun
|
||||
{
|
||||
tree->value[80] = 0;
|
||||
}
|
||||
sprintf(errmsg, "Unsupported clear command '%s'", tree->value);
|
||||
maxinfo_send_error(dcb, 0, errmsg);
|
||||
skygw_log_write(LE, errmsg);
|
||||
}
|
||||
|
||||
extern void shutdown_server();
|
||||
|
||||
/**
|
||||
* MaxScale shutdown
|
||||
* @param dcb Client DCB
|
||||
* @param tree Parse tree
|
||||
*/
|
||||
void exec_shutdown_maxscale(DCB *dcb, MAXINFO_TREE *tree)
|
||||
{
|
||||
shutdown_server();
|
||||
maxinfo_send_ok(dcb);
|
||||
}
|
||||
|
||||
/**
|
||||
* Stop a monitor
|
||||
* @param dcb Client DCB
|
||||
* @param tree Parse tree
|
||||
*/
|
||||
void exec_shutdown_monitor(DCB *dcb, MAXINFO_TREE *tree)
|
||||
{
|
||||
char errmsg[120];
|
||||
if (tree && tree->value)
|
||||
{
|
||||
MONITOR* monitor = monitor_find(tree->value);
|
||||
if (monitor)
|
||||
{
|
||||
monitorStop(monitor);
|
||||
maxinfo_send_ok(dcb);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (strlen(tree->value) > 80) // Prevent buffer overrun
|
||||
{
|
||||
tree->value[80] = 0;
|
||||
}
|
||||
sprintf(errmsg, "Invalid argument '%s'", tree->value);
|
||||
maxinfo_send_error(dcb, 0, errmsg);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
sprintf(errmsg, "Missing argument for 'SHUTDOWN MONITOR'");
|
||||
maxinfo_send_error(dcb, 0, errmsg);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Stop a service
|
||||
* @param dcb Client DCB
|
||||
* @param tree Parse tree
|
||||
*/
|
||||
void exec_shutdown_service(DCB *dcb, MAXINFO_TREE *tree)
|
||||
{
|
||||
char errmsg[120];
|
||||
if (tree && tree->value)
|
||||
{
|
||||
SERVICE* service = service_find(tree->value);
|
||||
if (service)
|
||||
{
|
||||
serviceStop(service);
|
||||
maxinfo_send_ok(dcb);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (strlen(tree->value) > 80) // Prevent buffer overrun
|
||||
{
|
||||
tree->value[80] = 0;
|
||||
}
|
||||
sprintf(errmsg, "Invalid argument '%s'", tree->value);
|
||||
maxinfo_send_error(dcb, 0, errmsg);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
sprintf(errmsg, "Missing argument for 'SHUTDOWN SERVICE'");
|
||||
maxinfo_send_error(dcb, 0, errmsg);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The table of shutdown commands that are supported
|
||||
*/
|
||||
static struct
|
||||
{
|
||||
char *name;
|
||||
void (*func)(DCB *, MAXINFO_TREE *);
|
||||
} shutdown_commands[] = {
|
||||
{ "maxscale", exec_shutdown_maxscale},
|
||||
{ "monitor", exec_shutdown_monitor},
|
||||
{ "service", exec_shutdown_service},
|
||||
{ NULL, NULL}
|
||||
};
|
||||
|
||||
/**
|
||||
* Execute a shutdown command parse tree and return OK or runtime error
|
||||
*
|
||||
* @param dcb The DCB that connects to the client
|
||||
* @param tree The parse tree for the query
|
||||
*/
|
||||
static void
|
||||
exec_shutdown(DCB *dcb, MAXINFO_TREE *tree)
|
||||
{
|
||||
int i;
|
||||
char errmsg[120];
|
||||
|
||||
for (i = 0; shutdown_commands[i].name; i++)
|
||||
{
|
||||
if (strcasecmp(shutdown_commands[i].name, tree->value) == 0)
|
||||
{
|
||||
(*shutdown_commands[i].func)(dcb, tree->right);
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (strlen(tree->value) > 80) // Prevent buffer overrun
|
||||
{
|
||||
tree->value[80] = 0;
|
||||
}
|
||||
sprintf(errmsg, "Unsupported shutdown command '%s'", tree->value);
|
||||
maxinfo_send_error(dcb, 0, errmsg);
|
||||
skygw_log_write(LE, errmsg);
|
||||
}
|
||||
|
||||
/**
|
||||
* Restart a monitor
|
||||
* @param dcb Client DCB
|
||||
* @param tree Parse tree
|
||||
*/
|
||||
void exec_restart_monitor(DCB *dcb, MAXINFO_TREE *tree)
|
||||
{
|
||||
char errmsg[120];
|
||||
if (tree && tree->value)
|
||||
{
|
||||
MONITOR* monitor = monitor_find(tree->value);
|
||||
if (monitor)
|
||||
{
|
||||
monitorStart(monitor, NULL);
|
||||
maxinfo_send_ok(dcb);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (strlen(tree->value) > 80) // Prevent buffer overrun
|
||||
{
|
||||
tree->value[80] = 0;
|
||||
}
|
||||
sprintf(errmsg, "Invalid argument '%s'", tree->value);
|
||||
maxinfo_send_error(dcb, 0, errmsg);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
sprintf(errmsg, "Missing argument for 'RESTART MONITOR'");
|
||||
maxinfo_send_error(dcb, 0, errmsg);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Restart a service
|
||||
* @param dcb Client DCB
|
||||
* @param tree Parse tree
|
||||
*/
|
||||
void exec_restart_service(DCB *dcb, MAXINFO_TREE *tree)
|
||||
{
|
||||
char errmsg[120];
|
||||
if (tree && tree->value)
|
||||
{
|
||||
SERVICE* service = service_find(tree->value);
|
||||
if (service)
|
||||
{
|
||||
serviceRestart(service);
|
||||
maxinfo_send_ok(dcb);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (strlen(tree->value) > 80) // Prevent buffer overrun
|
||||
{
|
||||
tree->value[80] = 0;
|
||||
}
|
||||
sprintf(errmsg, "Invalid argument '%s'", tree->value);
|
||||
maxinfo_send_error(dcb, 0, errmsg);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
sprintf(errmsg, "Missing argument for 'RESTART SERVICE'");
|
||||
maxinfo_send_error(dcb, 0, errmsg);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The table of restart commands that are supported
|
||||
*/
|
||||
static struct
|
||||
{
|
||||
char *name;
|
||||
void (*func)(DCB *, MAXINFO_TREE *);
|
||||
} restart_commands[] = {
|
||||
{ "monitor", exec_restart_monitor},
|
||||
{ "service", exec_restart_service},
|
||||
{ NULL, NULL}
|
||||
};
|
||||
|
||||
/**
|
||||
* Execute a restart command parse tree and return OK or runtime error
|
||||
*
|
||||
* @param dcb The DCB that connects to the client
|
||||
* @param tree The parse tree for the query
|
||||
*/
|
||||
static void
|
||||
exec_restart(DCB *dcb, MAXINFO_TREE *tree)
|
||||
{
|
||||
int i;
|
||||
char errmsg[120];
|
||||
|
||||
for (i = 0; restart_commands[i].name; i++)
|
||||
{
|
||||
if (strcasecmp(restart_commands[i].name, tree->value) == 0)
|
||||
{
|
||||
(*restart_commands[i].func)(dcb, tree->right);
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (strlen(tree->value) > 80) // Prevent buffer overrun
|
||||
{
|
||||
tree->value[80] = 0;
|
||||
}
|
||||
sprintf(errmsg, "Unsupported restart command '%s'", tree->value);
|
||||
maxinfo_send_error(dcb, 0, errmsg);
|
||||
skygw_log_write(LE, errmsg);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the current MaxScale version
|
||||
*
|
||||
@ -764,3 +1228,25 @@ extern char *strcasestr();
|
||||
return rval;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Send an OK packet to the client.
|
||||
* @param dcb The DCB that connects to the client
|
||||
*/
|
||||
void maxinfo_send_ok(DCB *dcb)
|
||||
{
|
||||
static const char ok_packet[] ={
|
||||
0x07, 0x00, 0x00, 0x01,
|
||||
0x00, 0x00, 0x00,
|
||||
0x00, 0x00,
|
||||
0x00, 0x00
|
||||
};
|
||||
|
||||
GWBUF* buffer = gwbuf_alloc(sizeof(ok_packet));
|
||||
|
||||
if (buffer)
|
||||
{
|
||||
memcpy(buffer->start, ok_packet, sizeof(ok_packet));
|
||||
dcb->func.write(dcb, buffer);
|
||||
}
|
||||
}
|
||||
|
@ -50,7 +50,8 @@ static void free_tree(MAXINFO_TREE *);
|
||||
static char *fetch_token(char *, int *, char **);
|
||||
static MAXINFO_TREE *parse_column_list(char **sql);
|
||||
static MAXINFO_TREE *parse_table_name(char **sql);
|
||||
|
||||
MAXINFO_TREE* maxinfo_parse_literals(MAXINFO_TREE *tree, int min_args, char *ptr,
|
||||
PARSE_ERROR *parse_error);
|
||||
|
||||
/**
|
||||
* Parse a SQL subset for the maxinfo plugin and return a parse tree
|
||||
@ -111,6 +112,67 @@ MAXINFO_TREE *col, *table;
|
||||
table = parse_table_name(&ptr);
|
||||
return make_tree_node(MAXOP_SELECT, NULL, col, table);
|
||||
#endif
|
||||
case LT_FLUSH:
|
||||
free(text); // not needed
|
||||
ptr = fetch_token(ptr, &token, &text);
|
||||
return make_tree_node(MAXOP_FLUSH, text, NULL, NULL);
|
||||
|
||||
case LT_SHUTDOWN:
|
||||
free(text);
|
||||
ptr = fetch_token(ptr, &token, &text);
|
||||
tree = make_tree_node(MAXOP_SHUTDOWN, text, NULL, NULL);
|
||||
|
||||
if ((ptr = fetch_token(ptr, &token, &text)) == NULL)
|
||||
{
|
||||
/** Possibly SHUTDOWN MAXSCALE */
|
||||
return tree;
|
||||
}
|
||||
tree->right = make_tree_node(MAXOP_LITERAL, text, NULL, NULL);
|
||||
|
||||
if ((ptr = fetch_token(ptr, &token, &text)) != NULL)
|
||||
{
|
||||
/** Unknown token after SHUTDOWN MONITOR|SERVICE */
|
||||
*parse_error = PARSE_SYNTAX_ERROR;
|
||||
free_tree(tree);
|
||||
return NULL;
|
||||
}
|
||||
return tree;
|
||||
|
||||
case LT_RESTART:
|
||||
free(text);
|
||||
ptr = fetch_token(ptr, &token, &text);
|
||||
tree = make_tree_node(MAXOP_RESTART, text, NULL, NULL);
|
||||
|
||||
if ((ptr = fetch_token(ptr, &token, &text)) == NULL)
|
||||
{
|
||||
/** Missing token for RESTART MONITOR|SERVICE */
|
||||
*parse_error = PARSE_SYNTAX_ERROR;
|
||||
free_tree(tree);
|
||||
return NULL;
|
||||
}
|
||||
tree->right = make_tree_node(MAXOP_LITERAL, text, NULL, NULL);
|
||||
|
||||
if ((ptr = fetch_token(ptr, &token, &text)) != NULL)
|
||||
{
|
||||
/** Unknown token after RESTART MONITOR|SERVICE */
|
||||
*parse_error = PARSE_SYNTAX_ERROR;
|
||||
free_tree(tree);
|
||||
return NULL;
|
||||
}
|
||||
return tree;
|
||||
|
||||
case LT_SET:
|
||||
free(text); // not needed
|
||||
ptr = fetch_token(ptr, &token, &text);
|
||||
tree = make_tree_node(MAXOP_SET, text, NULL, NULL);
|
||||
return maxinfo_parse_literals(tree, 2, ptr, parse_error);
|
||||
|
||||
case LT_CLEAR:
|
||||
free(text); // not needed
|
||||
ptr = fetch_token(ptr, &token, &text);
|
||||
tree = make_tree_node(MAXOP_CLEAR, text, NULL, NULL);
|
||||
return maxinfo_parse_literals(tree, 2, ptr, parse_error);
|
||||
break;
|
||||
default:
|
||||
*parse_error = PARSE_SYNTAX_ERROR;
|
||||
return NULL;
|
||||
@ -231,18 +293,24 @@ free_tree(MAXINFO_TREE *tree)
|
||||
/**
|
||||
* The set of keywords known to the tokeniser
|
||||
*/
|
||||
static struct {
|
||||
char *text;
|
||||
int token;
|
||||
static struct
|
||||
{
|
||||
char *text;
|
||||
int token;
|
||||
} keywords[] = {
|
||||
{ "show", LT_SHOW },
|
||||
{ "select", LT_SELECT },
|
||||
{ "from", LT_FROM },
|
||||
{ "like", LT_LIKE },
|
||||
{ "=", LT_EQUAL },
|
||||
{ ",", LT_COMMA },
|
||||
{ "*", LT_STAR },
|
||||
{ NULL, 0 }
|
||||
{ "show", LT_SHOW},
|
||||
{ "select", LT_SELECT},
|
||||
{ "from", LT_FROM},
|
||||
{ "like", LT_LIKE},
|
||||
{ "=", LT_EQUAL},
|
||||
{ ",", LT_COMMA},
|
||||
{ "*", LT_STAR},
|
||||
{ "flush", LT_FLUSH},
|
||||
{ "set", LT_SET},
|
||||
{ "clear", LT_CLEAR},
|
||||
{ "shutdown", LT_SHUTDOWN},
|
||||
{ "restart", LT_RESTART},
|
||||
{ NULL, 0}
|
||||
};
|
||||
|
||||
/**
|
||||
@ -322,3 +390,36 @@ int i;
|
||||
*token = LT_STRING;
|
||||
return s2;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse the remaining arguments as literals.
|
||||
* @param tree Previous head of the parse tree
|
||||
* @param min_args Minimum required number of arguments
|
||||
* @param ptr Pointer to client command
|
||||
* @param parse_error Pointer to parsing error to fill
|
||||
* @return Parsed tree or NULL if parsing failed
|
||||
*/
|
||||
MAXINFO_TREE* maxinfo_parse_literals(MAXINFO_TREE *tree, int min_args, char *ptr,
|
||||
PARSE_ERROR *parse_error)
|
||||
{
|
||||
int token;
|
||||
MAXINFO_TREE* node = tree;
|
||||
char *text;
|
||||
for(int i = 0; i < min_args; i++)
|
||||
{
|
||||
if((ptr = fetch_token(ptr, &token, &text)) == NULL ||
|
||||
(node->right = make_tree_node(MAXOP_LITERAL, text, NULL, NULL)) == NULL)
|
||||
{
|
||||
*parse_error = PARSE_SYNTAX_ERROR;
|
||||
free_tree(tree);
|
||||
if(ptr)
|
||||
{
|
||||
free(text);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
node = node->right;
|
||||
}
|
||||
|
||||
return tree;
|
||||
}
|
||||
|
@ -55,11 +55,11 @@
|
||||
# define ss_dassert(exp) if(!(exp)){(skygw_log_write(LE,\
|
||||
"debug assert %s:%d\n", \
|
||||
(char*)__FILE__, \
|
||||
__LINE__));skygw_log_sync_all();assert(exp);}
|
||||
__LINE__));mxs_log_flush_sync();assert(exp);}
|
||||
#define ss_info_dassert(exp,info) if(!(exp)){(skygw_log_write(LE,\
|
||||
"debug assert %s:%d %s\n", \
|
||||
(char*)__FILE__, \
|
||||
__LINE__,info));skygw_log_sync_all();assert(exp);}
|
||||
__LINE__,info));mxs_log_flush_sync();assert(exp);}
|
||||
# define ss_debug(exp) exp
|
||||
# define ss_dfprintf fprintf
|
||||
# define ss_dfflush fflush
|
||||
|
Loading…
x
Reference in New Issue
Block a user