Merge branch 'develop' into MAX-324

Conflicts:
	server/include/modutil.h
This commit is contained in:
Markus Makela 2015-03-09 10:18:59 +02:00
commit 5471d35524
24 changed files with 1169 additions and 112 deletions

View File

@ -7,11 +7,12 @@ The firewall filter is used to block queries that match a set of rules. It can b
The firewall filter only requires a minimal set of configurations in the MaxScale.cnf file. The actual rules of the firewall filter are located in a separate text file. The following is an example of a firewall filter configuration in the MaxScale.cnf file.
[Firewall]
type=filter
module=fwfilter
rules=/home/user/rules.txt
```
[Firewall]
type=filter
module=fwfilter
rules=/home/user/rules.txt
```
### Filter Options
@ -25,9 +26,11 @@ The firewall filter has one mandatory parameter that defines the location of the
The rules are defined by using the following syntax.
` rule NAME deny [wildcard | columns VALUE ... |
regex REGEX | limit_queries COUNT TIMEPERIOD HOLDOFF |
no_where_clause] [at_times VALUE...] [on_queries [select|update|insert|delete]]`
```
rule NAME deny [wildcard | columns VALUE ... |
regex REGEX | limit_queries COUNT TIMEPERIOD HOLDOFF |
no_where_clause] [at_times VALUE...] [on_queries [select|update|insert|delete]]`
```
Rules always define a blocking action so the basic mode for the firewall filter is to allow all queries that do not match a given set of rules. Rules are identified by their name and have a mandatory part and optional parts.
@ -81,30 +84,38 @@ After this either the keyword `any` `all` or `strict_all` is expected. This defi
After the matching part comes the rules keyword after which a list of rule names is expected. This allows reusing of the rules and enables varying levels of query restriction.
## Examples
## Use Cases
### Example rule file
### Use Case 1 - Prevent rapid execution of specific queries
The following is an example of a rule file which defines six rules and applies them to three sets of users. This rule file is used in all of the examples.
To prevent the excessive use of a database we want to set a limit on the rate of queries. We only want to apply this limit to certain queries that cause unwanted behavior. To achieve this we can use a regular expression.
rule block_wildcard deny wildcard at_times 8:00:00-17:00:00
rule no_personal_info deny columns phone salary address on_queries select|delete at_times 12:00:00-18:00:00
rule simple_regex deny regex '.*insert.*into.*select.*'
rule dos_block deny limit_queries 10000 1.0 500.0 at_times 12:00:00-18:00:00
rule safe_delete deny no_where_clause on_queries delete
rule managers_table deny regex '.*from.*managers.*'
users John@% Jane@% match any rules no_personal_info block_wildcard
users %@80.120.% match any rules block_wildcard dos_block
users %@% match all rules safe_delete managers_table
First we define the limit on the rate of queries. The first parameter for the rule sets the number of allowed queries to 10 queries and the second parameter sets the rate of sampling to 5 seconds. If a user executes queries faster than this, any further queries that match the regular expression are blocked for 60 seconds.
### Example 1 - Deny access to personal information and prevent huge queries during peak hours
```
rule limit_rate_of_queries deny limit_queries 10 5 60
rule query_regex deny regex '.*select.*from.*user_data.*'
```
Assume that a database cluster with tables that have a large number of columns is under heavy load during certain times of the day. Now also assume that large selects and querying of personal information creates unwanted stress on the cluster. Now we wouldn't want to completely prevent all the users from accessing personal information or performing large select queries, we only want to block the users John and Jane.
To apply these rules we combine them into a single rule by adding a `users` line to the rule file.
This can be achieved by creating two rules. One that blocks the usage of the wildcard and one that prevents queries that target a set of columns. To apply these rules to the users we define a users line into the rule file with both the rules and all the users we want to apply the rules to. The rules are defined in the example rule file on line 1 and 2 and the users line is defined on line 7.
```
users %@% match all rules limit_rate_of_queries query_regex
```
### Example 2 - Only safe deletes into the managers table
### Use Case 2 - Only allow deletes with a where clause
We want to prevent accidental deletes into the managers table where the where clause is missing. This poses a problem, we don't want to require all the delete queries to have a where clause. We only want to prevent the data in the managers table from being deleted without a where clause.
We have a table which contains all the managers of a company. We want to prevent accidental deletes into this table where the where clause is missing. This poses a problem, we don't want to require all the delete queries to have a where clause. We only want to prevent the data in the managers table from being deleted without a where clause.
To achieve this, we need two rules. The first rule can be seen on line 5 in the example rule file. This defines that all delete operations must have a where clause. This rule alone does us no good so we need a second one. The second rule is defined on line 6 and it blocks all queries that match the provided regular expression. When we combine these two rules we get the result we want. You can see the application of these rules on line 9 of the example rule file. The usage of the `all` and `strict_all` matching mode requires that all the rules must match for the query to be blocked. This in effect combines the two rules into a more complex rule.
To achieve this, we need two rules. The first rule defines that all delete operations must have a where clause. This rule alone does us no good so we need a second one. The second rule blocks all queries that match a regular expression.
```
rule safe_delete deny no_where_clause on_queries delete
rule managers_table deny regex '.*from.*managers.*'
```
When we combine these two rules we get the result we want. To combine these two rules add the following line to the rule file.
```
users %@% match all rules safe_delete managers_table
```

44
plugins/nagios/README Normal file
View File

@ -0,0 +1,44 @@
MaxScale Nagios plugins, for Nagios 3.5.1
MaxScale must be configured with 'maxscaled' protocol for the administration interface
[AdminInterface]
type=service
router=cli
[AdminListener]
type=listener
service=AdminInterface
protocol=maxscaled
port=6603
1) copy check_maxscale_*.pl under /usr/lib64/nagios/plugins
2) copy maxscale_commands.cfg, server1.cfg to /etc/nagios/objects/
3) Edit /etc/nagios/nagios.cfg
add
cfg_file=/etc/nagios/objects/maxscale_commands.cfg
cfg_file=/etc/nagios/objects/server1.cfg
Please note:
- modify server IP address in server1.cfg, pointing to MaxScale server
- maxadmin executable must be in the nagios server
- default AdminInterface port is 6603
- default maxadmin executable path is /usr/local/skysql/maxscale/bin/maxadmin
It can be changed by -m option
Example related to server1.cfg
# Check MaxScale sessions, on the remote machine.
define service{
use local-service ; Name of service template to use
host_name server1
service_description MaxScale_sessions
check_command check_maxscale_resource!6603!admin!skysql!sessions!/path_to/maxadmin
notifications_enabled 0
}
4) Restart Nagios

View File

@ -0,0 +1,213 @@
#!/usr/bin/perl
#
#
#
# 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-2015
#
#
#
# @file check_maxscale_monitors.pl - Nagios plugin for MaxScale monitors
#
# Revision History
#
# Date Who Description
# 06-03-2015 Massimiliano Pinto Initial implementation
#
#use strict;
#use warnings;
use Getopt::Std;
my %opts;
my $TIMEOUT = 15; # we don't want to wait long for a response
my %ERRORS = ('UNKNOWN' , '3',
'OK', '0',
'WARNING', '1',
'CRITICAL', '2');
my $curr_script = "$0";
$curr_script =~ s{.*/}{};
sub usage {
my $rc = shift;
print <<"EOF";
MaxScale monitor checker plugin for Nagios
Usage: $curr_script [-r <resource>] [-H <host>] [-P <port>] [-u <user>] [-p <pass>] [-m <maxadmin>] [-h]
Options:
-r <resource> = monitors
-h = provide this usage message
-H <host> = which host to connect to
-P <port> = port to use
-u <user> = username to connect as
-p <pass> = password to use for <user> at <host>
-m <maxadmin> = /path/to/maxadmin
EOF
exit $rc;
}
%opts =(
'r' => 'monitors', # default maxscale resource to show
'h' => '', # give help
'H' => 'localhost', # host
'u' => 'root', # username
'p' => '', # password
'P' => 6603, # port
'm' => '/usr/local/skysql/maxscale/bin/maxadmin', # maxadmin
);
my $MAXADMIN_DEFAULT = $opts{'m'};
getopts('r:hH:u:p:P:m:', \%opts)
or usage( $ERRORS{"UNKNOWN"} );
usage( $ERRORS{'OK'} ) if $opts{'h'};
my $MAXADMIN_RESOURCE = $opts{'r'};
my $MAXADMIN = $opts{'m'};
if (!defined $MAXADMIN || length($MAXADMIN) == 0) {
$MAXADMIN = $MAXADMIN_DEFAULT;
}
-x $MAXADMIN or
die "$curr_script: Failed to find required tool: $MAXADMIN. Please install it or use the -m option to point to another location.";
# Just in case of problems, let's not hang Nagios
$SIG{'ALRM'} = sub {
print ("UNKNOWN: No response from MaxScale server (alarm)\n");
exit $ERRORS{"UNKNOWN"};
};
alarm($TIMEOUT);
my $command = $MAXADMIN . ' -h ' . $opts{'H'} . ' -u ' . $opts{'u'} . ' -p "' . $opts{'p'} . '" -P ' . $opts{'P'} . ' ' . "show " . $MAXADMIN_RESOURCE;
#print "maxadmin command: $command\n";
open (MAXSCALE, "$command 2>&1 |")
or die "can't get data out of Maxscale: $!";
my $hostname = qx{hostname}; chomp $hostname;
my $waiting_backend = 0;
my $service;
my $start_output = 0;
my $n_threads = 0;
my $p_threads = 0;
my $performance_data="";
my $resource_type = $MAXADMIN_RESOURCE;
chop($resource_type);
my $resource_match = ucfirst("$resource_type Name");
my $this_key;
my %monitor_data;
while ( <MAXSCALE> ) {
chomp;
if ( /(Failed|Unable) to connect to MaxScale/ ) {
printf "CRITICAL: $_\n";
close(MAXSCALE);
exit(2);
}
if ( /^Monitor\:/ ) {
$n_threads++;
$this_key = 'monitor' . $n_threads;
$monitor_data{$this_key} = {
'1name'=> '',
'2state' => '',
'3servers' => '',
'4interval' => '',
'5repl_lag' => ''
};
next;
}
next if (/--/ || $_ eq '');
if ( /\s+Name/) {
my $str;
my $perf_line;
my @data_row = split(':', $_);
my $name = $data_row[1];
$name =~ s/^\s+|\s+$//g;
$monitor_data{$this_key}{'1name'}=$name;
}
if (/(\s+Monitor )(.*)/) {
$monitor_data{$this_key}{'2state'}=$2;
}
if ( /Monitored servers\:/ ) {
my $server_list;
my @data_row = split(':', $_);
shift(@data_row);
foreach my $name (@data_row) {
$name =~ s/^\s+|\s+$//g;
$name =~ s/ //g;
$server_list .= $name . ":";
}
chop($server_list);
$monitor_data{$this_key}{'3servers'}=$server_list;
}
if ( /(Sampling interval\:)\s+(\d+) milliseconds/ ) {
#my @data_row = split(':', $_);
#my $name = $data_row[1];
#$name =~ s/^\s+|\s+$//g;
#$monitor_data{$this_key}{'4interval'}=$name;
$monitor_data{$this_key}{'4interval'}=$2;
}
if ( /Replication lag\:/ ) {
my @data_row = split(':', $_);
my $name = $data_row[1];
$name =~ s/^\s+|\s+$//g;
$monitor_data{$this_key}{'5repl_lag'}=$name;
}
}
for my $key ( sort(keys %monitor_data) ) {
#print "-- key: [$key]\n";
my $local_hash = {};
$performance_data .= " $key=";
$local_hash = $monitor_data{$key};
my %new_hash = %$local_hash;
foreach my $key (sort (keys (%new_hash))) {
$performance_data .= $new_hash{$key} . ";";
}
}
chop($performance_data);
if ($n_threads) {
printf "OK: %d monitors found |%s\n", $n_threads, $performance_data;
close(MAXSCALE);
exit 0;
} else {
printf "CRITICAL: 0 monitors found\n";
close(MAXSCALE);
exit 2;
}

View File

@ -0,0 +1,181 @@
#!/usr/bin/perl
#
#
#
# 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-2015
#
#
#
# @file check_maxscale_resources.pl - Nagios plugin for MaxScale resources
#
# Revision History
#
# Date Who Description
# 06-03-2015 Massimiliano Pinto Initial implementation
#
#use strict;
#use warnings;
use Getopt::Std;
my %opts;
my $TIMEOUT = 15; # we don't want to wait long for a response
my %ERRORS = ('UNKNOWN' , '3',
'OK', '0',
'WARNING', '1',
'CRITICAL', '2');
my $curr_script = "$0";
$curr_script =~ s{.*/}{};
sub usage {
my $rc = shift;
print <<"EOF";
MaxScale monitor checker plugin for Nagios
Usage: $curr_script [-r <resource>] [-H <host>] [-P <port>] [-u <user>] [-p <pass>] [-m <maxadmin>] [-h]
Options:
-r <resource> = modules|services|filters|listeners|servers|sessions
-h = provide this usage message
-H <host> = which host to connect to
-P <port> = port to use
-u <user> = username to connect as
-p <pass> = password to use for <user> at <host>
-m <maxadmin> = /path/to/maxadmin
EOF
exit $rc;
}
%opts =(
'r' => 'services', # default maxscale resource to show
'h' => '', # give help
'H' => 'localhost', # host
'u' => 'root', # username
'p' => '', # password
'P' => 6603, # port
'm' => '/usr/local/skysql/maxscale/bin/maxadmin', # maxadmin
);
my $MAXADMIN_DEFAULT = $opts{'m'};
getopts('r:hH:u:p:P:m:', \%opts)
or usage( $ERRORS{"UNKNOWN"} );
usage( $ERRORS{'OK'} ) if $opts{'h'};
my $MAXADMIN_RESOURCE = $opts{'r'};
my $MAXADMIN = $opts{'m'};
if (!defined $MAXADMIN || length($MAXADMIN) == 0) {
$MAXADMIN = $MAXADMIN_DEFAULT;
}
-x $MAXADMIN or
die "$curr_script: Failed to find required tool: $MAXADMIN. Please install it or use the -m option to point to another location.";
# Just in case of problems, let's not hang Nagios
$SIG{'ALRM'} = sub {
print ("UNKNOWN: No response from MaxScale server (alarm)\n");
exit $ERRORS{"UNKNOWN"};
};
alarm($TIMEOUT);
my $command = $MAXADMIN . ' -h ' . $opts{'H'} . ' -u ' . $opts{'u'} . ' -p "' . $opts{'p'} . '" -P ' . $opts{'P'} . ' ' . "list " . $MAXADMIN_RESOURCE;
#print "maxadmin command: $command\n";
open (MAXSCALE, "$command 2>&1 |")
or die "can't get data out of Maxscale: $!";
my $hostname = qx{hostname}; chomp $hostname;
my $waiting_backend = 0;
my $service;
my $start_output = 0;
my $n_threads = 0;
my $p_threads = 0;
my $performance_data="";
my $resource_type = $MAXADMIN_RESOURCE;
chop($resource_type);
my $resource_match = ucfirst("$resource_type Name");
if ($resource_type eq "listener") {
$resource_match = "Service Name";
}
if ($resource_type eq "filter") {
$resource_match = "Filter";
}
if ($resource_type eq "server") {
$resource_match = "Server";
}
if ($resource_type eq "session") {
$resource_match = "Session";
}
#print "Matching [$resource_match]\n";
while ( <MAXSCALE> ) {
chomp;
if ( /(Failed|Unable) to connect to MaxScale/ ) {
printf "CRITICAL: $_\n";
close(MAXSCALE);
exit(2);
}
if ( ! /^$resource_match/ ) {
} else {
$start_output = 1;
next;
}
if ($start_output) {
next if (/--/ || $_ eq '');
$n_threads++;
if ($resource_type ne "session") {
my $str;
my $perf_line;
my @data_row = split('\|', $_);
$performance_data .= "module$n_threads=";
foreach my $val (@data_row) {
$str = $val;
$str =~ s/^\s+|\s+$//g;
$perf_line .= $str . ';';
}
chop($perf_line);
$performance_data .= $perf_line . ' ';
}
}
}
chop($performance_data);
if ($n_threads) {
if ($performance_data eq '') {
printf "OK: %d $MAXADMIN_RESOURCE found\n", $n_threads;
} else {
printf "OK: %d $MAXADMIN_RESOURCE found | %s\n", $n_threads, $performance_data;
}
close(MAXSCALE);
exit 0;
} else {
printf "CRITICAL: 0 $MAXADMIN_RESOURCE found\n";
close(MAXSCALE);
exit 2;
}

View File

@ -0,0 +1,244 @@
#!/usr/bin/perl
#
#
#
# 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-2015
#
#
#
# @file check_maxscale_threads.pl - Nagios plugin for MaxScale threads and events
#
# Revision History
#
# Date Who Description
# 06-03-2015 Massimiliano Pinto Initial implementation
#
#use strict;
#use warnings;
use Getopt::Std;
my %opts;
my $TIMEOUT = 15; # we don't want to wait long for a response
my %ERRORS = ('UNKNOWN' , '3',
'OK', '0',
'WARNING', '1',
'CRITICAL', '2');
my $curr_script = "$0";
$curr_script =~ s{.*/}{};
sub usage {
my $rc = shift;
print <<"EOF";
MaxScale monitor checker plugin for Nagios
Usage: $curr_script [-r <resource>] [-H <host>] [-P <port>] [-u <user>] [-p <pass>] [-m <maxadmin>] [-h]
Options:
-r <resource> = threads
-h = provide this usage message
-H <host> = which host to connect to
-P <port> = port to use
-u <user> = username to connect as
-p <pass> = password to use for <user> at <host>
-m <maxadmin> = /path/to/maxadmin
EOF
exit $rc;
}
%opts =(
'r' => 'threads', # default maxscale resource to show
'h' => '', # give help
'H' => 'localhost', # host
'u' => 'root', # username
'p' => '', # password
'P' => 6603, # port
'm' => '/usr/local/skysql/maxscale/bin/maxadmin', # maxadmin
);
my $MAXADMIN_DEFAULT = $opts{'m'};
getopts('r:hH:u:p:P:m:', \%opts)
or usage( $ERRORS{"UNKNOWN"} );
usage( $ERRORS{'OK'} ) if $opts{'h'};
my $MAXADMIN_RESOURCE = $opts{'r'};
my $MAXADMIN = $opts{'m'};
if (!defined $MAXADMIN || length($MAXADMIN) == 0) {
$MAXADMIN = $MAXADMIN_DEFAULT;
}
-x $MAXADMIN or
die "$curr_script: Failed to find required tool: $MAXADMIN. Please install it or use the -m option to point to another location.";
# Just in case of problems, let's not hang Nagios
$SIG{'ALRM'} = sub {
print ("UNKNOWN: No response from MaxScale server (alarm)\n");
exit $ERRORS{"UNKNOWN"};
};
alarm($TIMEOUT);
my $command = $MAXADMIN . ' -h ' . $opts{'H'} . ' -u ' . $opts{'u'} . ' -p "' . $opts{'p'} . '" -P ' . $opts{'P'} . ' ' . "show " . $MAXADMIN_RESOURCE;
#print "maxadmin command: $command\n";
open (MAXSCALE, "$command 2>&1 |")
or die "can't get data out of Maxscale: $!";
my $hostname = qx{hostname}; chomp $hostname;
my $waiting_backend = 0;
my $service;
my $start_output = 0;
my $n_threads = 0;
my $p_threads = 0;
my $performance_data="";
my $resource_type = $MAXADMIN_RESOURCE;
chop($resource_type);
my $resource_match = ucfirst("$resource_type Name");
my $historic_thread_load_average = 0;
my $current_thread_load_average = 0;
my %thread_data;
my %event_data;
my $start_queue_len = 0;
while ( <MAXSCALE> ) {
chomp;
if ( /(Failed|Unable) to connect to MaxScale/ ) {
printf "CRITICAL: $_\n";
close(MAXSCALE);
exit(2);
}
if ( /Historic Thread Load Average/) {
my $str;
my @data_row = split(':', $_);
foreach my $val (@data_row) {
$str = $val;
$str =~ s/^\s+|\s+$//g;
}
chop($str);
$historic_thread_load_average = $str;
}
if (/Current Thread Load Average/) {
my $str;
my @data_row = split(':', $_);
foreach my $val (@data_row) {
$str = $val;
$str =~ s/^\s+|\s+$//g;
}
chop($str);
$current_thread_load_average = $str;
}
if (/Minute Average/) {
my $str;
my $in_str;
my @data_row = split(',', $_);
foreach my $val (@data_row) {
my ($i,$j)= split(':', $val);
$i =~ s/^\s+|\s+$//g;
$j =~ s/^\s+|\s+$//g;
if ($start_queue_len) {
$event_data{$i} = $j;
} else {
$thread_data{$i} = $j;
}
}
}
if ( /Pending event queue length averages/) {
$start_queue_len = 1;
next;
}
if ( ! /^\s+ID/ ) {
#printf $_ ."\n";
} else {
#printf "[$_]" ."\n";
$start_output = 1;
next;
}
if ($start_output && /^\s+\d/) {
#printf "Thread [$_]" . "\n";
$n_threads++;
if (/Processing/) {
$p_threads++;
}
}
}
close(MAXSCALE);
open( MAXSCALE, "/servers/maxinfo/bin/maxadmin -h 127.0.0.1 -P 8444 -uadmin -pskysql show epoll 2>&1 |" )
or die "can't get data out of Maxscale: $!";
my $queue_len = 0;
while ( <MAXSCALE> ) {
chomp;
if ( ! /Current event queue length/ ) {
next;
} else {
my $str;
my @data_row = split(':', $_);
foreach my $val (@data_row) {
$str = $val;
$str =~ s/^\s+|\s+$//g;
}
$queue_len = $str;
last;
}
}
my $performance_data = "";
my $performance_data_thread = "";
my $performance_data_event = "";
my $in_str;
my $in_key;
my $in_val;
my @new_thread_array = @thread_data{'15 Minute Average', '5 Minute Average', '1 Minute Average'};
my @new_event_array = @event_data{'15 Minute Average', '5 Minute Average', '1 Minute Average'};
$performance_data_thread = join(';', @new_thread_array);
$performance_data_event = join(';', @new_event_array);
$performance_data .= "threads=$historic_thread_load_average;$current_thread_load_average avg_threads=$performance_data_thread avg_events=$performance_data_event";
if ($p_threads < $n_threads) {
printf "OK: Processing threads: %d/%d Events: %d | $performance_data\n", $p_threads, $n_threads, $queue_len;
close(MAXSCALE);
exit 0;
} else {
printf "WARNING: Processing threads: %d/%d Events: %d | $performance_data\n", $p_threads, $n_threads, $queue_len;
close(MAXSCALE);
exit 1;
}

View File

@ -0,0 +1,31 @@
###############################################################################
# MAXSCALE_COMMANDS.CFG - SAMPLE COMMAND DEFINITIONS FOR NAGIOS 3.5.1
#
# Last Modified: 06-03-2015
#
# NOTES: This config file provides you with some example command definitions
# that you can reference in host, service, and contact definitions.
#
# You don't need to keep commands in a separate file from your other
# object definitions. This has been done just to make things easier to
# understand.
#
###############################################################################
# check maxscale monitors
define command{
command_name check_maxscale_monitors
command_line $USER1$/check_maxscale_monitors.pl -H $HOSTADDRESS$ -P $ARG1$ -u $ARG2$ -p $ARG3$ -r $ARG4$ -m $ARG5$
}
# check maxscale threads
define command{
command_name check_maxscale_threads
command_line $USER1$/check_maxscale_threads.pl -H $HOSTADDRESS$ -P $ARG1$ -u $ARG2$ -p $ARG3$ -r $ARG4$ -m $ARG5$
}
# check maxscale resource (listeners, services, etc)
define command{
command_name check_maxscale_resource
command_line $USER1$/check_maxscale_resources.pl -H $HOSTADDRESS$ -P $ARG1$ -u $ARG2$ -p $ARG3$ -r $ARG4$ -m $ARG5$
}

111
plugins/nagios/server1.cfg Normal file
View File

@ -0,0 +1,111 @@
###############################################################################
###############################################################################
#
# HOST DEFINITION
#
###############################################################################
###############################################################################
# Define a host for the remote machine
define host{
use linux-server ; Name of host template to use
; This host definition will inherit all variables that are defined
; in (or inherited by) the linux-server host template definition.
host_name server1
alias server1
address xxx.xxx.xxx.xxx
}
###############################################################################
###############################################################################
#
# HOST GROUP DEFINITION
#
###############################################################################
###############################################################################
# Define an optional hostgroup for Linux machines
define hostgroup{
hostgroup_name linux-real-servers ; The name of the hostgroup
alias Linux Real Servers ; Long name of the group
members server1 ; Comma separated list of hosts that belong to this group
}
# Check MaxScale modules, on the remote machine.
define service{
use local-service ; Name of service template to use
host_name server1
service_description MaxScale_modules
check_command check_maxscale_resource!6603!admin!skysql!modules
notifications_enabled 0
}
# Check MaxScale services, on the remote machine.
define service{
use local-service ; Name of service template to use
host_name server1
service_description MaxScale_services
check_command check_maxscale_resource!6603!admin!skysql!services
notifications_enabled 0
}
# Check MaxScale listeners, on the remote machine.
define service{
use local-service ; Name of service template to use
host_name server1
service_description MaxScale_listeners
check_command check_maxscale_resource!6603!admin!skysql!listeners
notifications_enabled 0
}
# Check MaxScale servers, on the remote machine.
define service{
use local-service ; Name of service template to use
host_name server1
service_description MaxScale_servers
check_command check_maxscale_resource!6603!admin!skysql!servers
notifications_enabled 0
}
# Check MaxScale sessions, on the remote machine.
define service{
use local-service ; Name of service template to use
host_name server1
service_description MaxScale_sessions
check_command check_maxscale_resource!6603!admin!skysql!sessions
notifications_enabled 0
}
# Check MaxScale filters, on the remote machine.
define service{
use local-service ; Name of service template to use
host_name server1
service_description MaxScale_filters
check_command check_maxscale_resource!6603!admin!skysql!filters
notifications_enabled 0
}
# Check MaxScale monitors, on the remote machine.
define service{
use local-service ; Name of service template to use
host_name server1
service_description MaxScale_monitors
check_command check_maxscale_monitors!6603!admin!skysql!monitors
notifications_enabled 0
}
# Define a service to check Script on the remote machine.
define service{
use local-service ; Name of service template to use
host_name server1
service_description MaxScale_threads
check_command check_maxscale_threads!6603!admin!skysql!threads
notifications_enabled 0
}

View File

@ -253,7 +253,9 @@ char* admin_remove_user(
/**
* Open passwd file and remove user from the file.
*/
if ((home = getenv("MAXSCALE_HOME")) != NULL && strlen(home) < 1024) {
if ((home = getenv("MAXSCALE_HOME")) != NULL &&
strnlen(home,PATH_MAX) < PATH_MAX &&
strnlen(home,PATH_MAX) > 0) {
sprintf(fname, "%s/etc/passwd", home);
sprintf(fname_tmp, "%s/etc/passwd_tmp", home);
} else {

View File

@ -558,7 +558,7 @@ GWBUF* modutil_get_complete_packets(GWBUF** p_readbuf)
* @return Number of EOF packets
*/
int
modutil_count_signal_packets(GWBUF *reply, int use_ok, int n_found)
modutil_count_signal_packets(GWBUF *reply, int use_ok, int n_found, int* more)
{
unsigned char* ptr = (unsigned char*) reply->start;
unsigned char* end = (unsigned char*) reply->end;
@ -566,6 +566,7 @@ modutil_count_signal_packets(GWBUF *reply, int use_ok, int n_found)
int pktlen, eof = 0, err = 0;
int errlen = 0, eoflen = 0;
int iserr = 0, iseof = 0;
bool moreresults = false;
while(ptr < end)
{
@ -585,8 +586,9 @@ modutil_count_signal_packets(GWBUF *reply, int use_ok, int n_found)
}
}
if((ptr + pktlen) > end)
if((ptr + pktlen) > end || (eof + n_found) >= 2)
{
moreresults = PTR_EOF_MORE_RESULTS(ptr);
ptr = prev;
break;
}
@ -616,6 +618,8 @@ modutil_count_signal_packets(GWBUF *reply, int use_ok, int n_found)
}
}
*more = moreresults;
return(eof + err);
}
@ -693,3 +697,97 @@ static void modutil_reply_routing_error(
poll_add_epollin_event_to_dcb(backend_dcb, buf);
return;
}
/**
* Find the first occurrence of a character in a string. This function ignores
* escaped characters and all characters that are enclosed in single or double quotes.
* @param ptr Pointer to area of memory to inspect
* @param c Character to search for
* @param len Size of the memory area
* @return Pointer to the first non-escaped, non-quoted occurrence of the character.
* If the character is not found, NULL is returned.
*/
void* strnchr_esc(char* ptr,char c, int len)
{
char* p = (char*)ptr;
char* start = p;
bool quoted = false, escaped = false;
char qc;
while(p < start + len)
{
if(escaped)
{
escaped = false;
}
else if(*p == '\\')
{
escaped = true;
}
else if((*p == '\'' || *p == '"') && !quoted)
{
quoted = true;
qc = *p;
}
else if(quoted && *p == qc)
{
quoted = false;
}
else if(*p == c && !escaped && !quoted)
{
return p;
}
p++;
}
return NULL;
}
/**
* Create a COM_QUERY packet from a string.
* @param query Query to create.
* @return Pointer to GWBUF with the query or NULL if an error occurred.
*/
GWBUF* modutil_create_query(char* query)
{
if(query == NULL)
return NULL;
GWBUF* rval = gwbuf_alloc(strlen(query) + 5);
int pktlen = strlen(query) + 1;
unsigned char* ptr;
if(rval)
{
ptr = (unsigned char*)rval->start;
*ptr++ = (pktlen);
*ptr++ = (pktlen)>>8;
*ptr++ = (pktlen)>>16;
*ptr++ = 0x0;
*ptr++ = 0x03;
memcpy(ptr,query,strlen(query));
gwbuf_set_type(rval,GWBUF_TYPE_MYSQL);
}
return rval;
}
/**
* Count the number of statements in a query.
* @param buffer Buffer to analyze.
* @return Number of statements.
*/
int modutil_count_statements(GWBUF* buffer)
{
char* ptr = ((char*)(buffer)->start + 5);
char* end = ((char*)(buffer)->end);
int num = 1;
while((ptr = strnchr_esc(ptr,';', end - ptr)))
{
num++;
ptr++;
}
return num;
}

View File

@ -73,18 +73,19 @@ resultset_free(RESULTSET *resultset)
{
RESULT_COLUMN *col;
if (resultset)
return;
col = resultset->column;
while (col)
if (resultset != NULL)
{
RESULT_COLUMN *next;
col = resultset->column;
while (col)
{
RESULT_COLUMN *next;
next = col->next;
resultset_column_free(col);
col = next;
}
free(resultset);
}
free(resultset);
}
/**

View File

@ -42,6 +42,7 @@ static bool success = false;
int hup(DCB* dcb)
{
success = true;
return 1;
}
/**
@ -108,7 +109,8 @@ hkinit();
skygw_log_sync_all();
ss_info_dassert(0 != result, "Stop should succeed");
dcb = dcb_alloc(DCB_ROLE_REQUEST_HANDLER);
if((dcb = dcb_alloc(DCB_ROLE_REQUEST_HANDLER)) == NULL)
return 1;
ss_info_dassert(dcb != NULL, "DCB allocation failed");
session = session_alloc(service,dcb);

View File

@ -33,6 +33,7 @@
*/
#include <buffer.h>
#include <dcb.h>
#include <string.h>
#define PTR_IS_RESULTSET(b) (b[0] == 0x01 && b[1] == 0x0 && b[2] == 0x0 && b[3] == 0x01)
#define PTR_IS_EOF(b) (b[0] == 0x05 && b[1] == 0x0 && b[2] == 0x0 && b[4] == 0xfe)
@ -40,6 +41,8 @@
#define PTR_IS_ERR(b) (b[4] == 0xff)
#define PTR_IS_LOCAL_INFILE(b) (b[4] == 0xfb)
#define IS_FULL_RESPONSE(buf) (modutil_count_signal_packets(buf,0,0) == 2)
#define PTR_EOF_MORE_RESULTS(b) ((PTR_IS_EOF(b) && ptr[7] & 0x08))
extern int modutil_is_SQL(GWBUF *);
extern int modutil_is_SQL_prepare(GWBUF *);
@ -54,6 +57,8 @@ GWBUF* modutil_get_complete_packets(GWBUF** p_readbuf);
int modutil_MySQL_query_len(GWBUF* buf, int* nbytes_missing);
void modutil_reply_parse_error(DCB* backend_dcb, char* errstr, uint32_t flags);
void modutil_reply_auth_error(DCB* backend_dcb, char* errstr, uint32_t flags);
int modutil_count_statements(GWBUF* buffer);
GWBUF* modutil_create_query(char* query);
GWBUF *modutil_create_mysql_err_msg(
int packet_number,
@ -62,6 +67,5 @@ GWBUF *modutil_create_mysql_err_msg(
const char *statemsg,
const char *msg);
int modutil_count_signal_packets(GWBUF*,int,int);
int modutil_count_signal_packets(GWBUF*,int,int,int*);
#endif

View File

@ -34,9 +34,9 @@ add_library(namedserverfilter SHARED namedserverfilter.c)
target_link_libraries(namedserverfilter log_manager utils)
install(TARGETS namedserverfilter DESTINATION modules)
add_library(lagfilter SHARED lagfilter.c)
target_link_libraries(lagfilter log_manager utils query_classifier)
install(TARGETS lagfilter DESTINATION modules)
add_library(slavelag SHARED slavelag.c)
target_link_libraries(slavelag log_manager utils query_classifier)
install(TARGETS slavelag DESTINATION modules)
add_subdirectory(hint)

View File

@ -1558,6 +1558,7 @@ bool check_match_any(FW_INSTANCE* my_instance, FW_SESSION* my_session, GWBUF *qu
}
qlen = gw_mysql_get_byte3(memptr);
qlen = qlen < 0xffffff ? qlen : 0xffffff;
fullquery = malloc((qlen) * sizeof(char));
memcpy(fullquery,memptr + 5,qlen - 1);
memset(fullquery + qlen - 1,0,1);
@ -1612,6 +1613,7 @@ bool check_match_all(FW_INSTANCE* my_instance, FW_SESSION* my_session, GWBUF *qu
}
qlen = gw_mysql_get_byte3(memptr);
qlen = qlen < 0xffffff ? qlen : 0xffffff;
fullquery = malloc((qlen) * sizeof(char));
memcpy(fullquery,memptr + 5,qlen - 1);
memset(fullquery + qlen - 1,0,1);

View File

@ -32,7 +32,7 @@ extern size_t log_ses_count[];
extern __thread log_info_t tls_log_info;
/**
* @file lagfilter.c - a very simple filter designed to send queries to the
* @file slavelag.c - a very simple filter designed to send queries to the
* master server after data modification has occurred. This is done to prevent
* replication lag affecting the outcome of a select query.
*
@ -42,8 +42,11 @@ extern __thread log_info_t tls_log_info;
* is executed:
*
* count=<number of queries> Queries to route to master after data modification.
* time=<time period> Seconds to wait before queries are routed to slaves.
* time=<time period> Seconds to wait before queries are routed to slaves.
* match=<regex> Regex for matching
* ignore=<regex> Regex for ignoring
*
* The filter also has two options: @c case, which makes the regex case-sensitive, and @c ignorecase, which does the opposite.
* Date Who Description
* 03/03/2015 Markus Mäkelä Written for demonstrative purposes
* @endverbatim
@ -333,20 +336,20 @@ time_t now = time(NULL);
if(query_classifier_get_operation(queue) & (QUERY_OP_DELETE|QUERY_OP_INSERT|QUERY_OP_UPDATE))
{
sql = modutil_get_SQL(queue);
if(my_instance->nomatch == NULL||(my_instance->nomatch && regexec(&my_instance->nore,sql,0,NULL,0) != 0))
if((sql = modutil_get_SQL(queue)) != NULL)
{
if(my_instance->match == NULL||
(my_instance->match && regexec(&my_instance->re,sql,0,NULL,0) == 0))
if(my_instance->nomatch == NULL||(my_instance->nomatch && regexec(&my_instance->nore,sql,0,NULL,0) != 0))
{
my_session->hints_left = my_instance->count;
my_session->last_modification = now;
my_instance->stats.n_modified++;
if(my_instance->match == NULL||
(my_instance->match && regexec(&my_instance->re,sql,0,NULL,0) == 0))
{
my_session->hints_left = my_instance->count;
my_session->last_modification = now;
my_instance->stats.n_modified++;
}
}
free(sql);
}
free(sql);
}
else if(my_session->hints_left > 0)
{

View File

@ -63,7 +63,6 @@
#include <mysql_client_server_protocol.h>
#include <housekeeper.h>
#define MYSQL_COM_QUIT 0x01
#define MYSQL_COM_INITDB 0x02
#define MYSQL_COM_FIELD_LIST 0x04
@ -73,6 +72,7 @@
#define MYSQL_COM_STMT_SEND_LONG_DATA 0x18
#define MYSQL_COM_STMT_CLOSE 0x19
#define MYSQL_COM_STMT_RESET 0x1a
#define MYSQL_COM_CONNECT 0x1b
#define REPLY_TIMEOUT_SECOND 5
#define REPLY_TIMEOUT_MILLISECOND 1
@ -93,6 +93,7 @@ static unsigned char required_packets[] = {
MYSQL_COM_STMT_SEND_LONG_DATA,
MYSQL_COM_STMT_CLOSE,
MYSQL_COM_STMT_RESET,
MYSQL_COM_CONNECT,
0 };
/** Defined in log_manager.cc */
@ -163,20 +164,28 @@ typedef struct {
FILTER_DEF* dummy_filterdef;
int active; /* filter is active? */
bool use_ok;
int client_multistatement;
bool multipacket[2];
unsigned char command;
bool waiting[2]; /* if the client is waiting for a reply */
int eof[2];
int replies[2]; /* Number of queries received */
int reply_packets[2]; /* Number of OK, ERR, LOCAL_INFILE_REQUEST or RESULT_SET packets received */
DCB *branch_dcb; /* Client DCB for "branch" service */
SESSION *branch_session;/* The branch service session */
TEE_INSTANCE *instance;
int n_duped; /* Number of duplicated queries */
int n_rejected; /* Number of rejected queries */
int residual; /* Any outstanding SQL text */
GWBUF* tee_replybuf; /* Buffer for reply */
GWBUF* tee_partials[2];
GWBUF* querybuf;
SPINLOCK tee_lock;
DCB* client_dcb;
int statements; /*< Number of statements in the query,
* used to identify and track multi-statement
* queries and that both the parent and the child
* branch are in sync. */
#ifdef SS_DEBUG
long d_id;
#endif
@ -184,7 +193,8 @@ typedef struct {
typedef struct orphan_session_tt
{
SESSION* session;
SESSION* session; /*< The child branch session whose parent was freed before
* the child session was in a suitable state. */
struct orphan_session_tt* next;
}orphan_session_t;
@ -198,6 +208,7 @@ static orphan_session_t* allOrphans = NULL;
static SPINLOCK orphanLock;
static int packet_is_required(GWBUF *queue);
static int detect_loops(TEE_INSTANCE *instance, HASHTABLE* ht, SERVICE* session);
int internal_route(DCB* dcb);
static int hkfn(
void* key)
@ -498,7 +509,12 @@ char *remote, *userName;
{
my_session->active = 1;
my_session->residual = 0;
my_session->statements = 0;
my_session->tee_replybuf = NULL;
my_session->client_dcb = session->client;
my_session->instance = my_instance;
my_session->client_multistatement = false;
spinlock_init(&my_session->tee_lock);
if (my_instance->source &&
(remote = session_get_remote(session)) != NULL)
@ -544,7 +560,7 @@ char *remote, *userName;
goto retblock;
}
if((dummy = filter_alloc("tee_dummy","tee_dummy")) == NULL)
{
dcb_close(dcb);
@ -641,6 +657,7 @@ skygw_log_write(LOGFILE_TRACE,"Tee close: %d", atomic_add(&debug_seq,1));
#endif
if (my_session->active)
{
if ((bsession = my_session->branch_session) != NULL)
{
CHK_SESSION(bsession);
@ -675,7 +692,8 @@ skygw_log_write(LOGFILE_TRACE,"Tee close: %d", atomic_add(&debug_seq,1));
}
}
my_session->active = 0;
my_session->active = 0;
}
}
@ -800,11 +818,14 @@ char *ptr;
int length, rval, residual = 0;
GWBUF *clone = NULL;
unsigned char command = *((unsigned char*)queue->start + 4);
#ifdef SS_DEBUG
skygw_log_write(LOGFILE_TRACE,"Tee routeQuery: %d : %s",
atomic_add(&debug_seq,1),
((char*)queue->start + 5));
#endif
spinlock_acquire(&my_session->tee_lock);
if(!my_session->active)
@ -858,6 +879,8 @@ if(!my_session->active)
switch(command)
{
case 0x1b:
my_session->client_multistatement = *((unsigned char*) queue->start + 5);
case 0x03:
case 0x16:
case 0x17:
@ -871,8 +894,10 @@ if(!my_session->active)
}
memset(my_session->replies,0,2*sizeof(int));
memset(my_session->reply_packets,0,2*sizeof(int));
memset(my_session->eof,0,2*sizeof(int));
memset(my_session->waiting,1,2*sizeof(bool));
my_session->statements = modutil_count_statements(queue);
my_session->command = command;
#ifdef SS_DEBUG
spinlock_acquire(&debug_lock);
@ -938,6 +963,73 @@ if(!my_session->active)
return rval;
}
int count_replies(GWBUF* buffer)
{
unsigned char* ptr = (unsigned char*)buffer->start;
unsigned char* end = (unsigned char*) buffer->end;
int pktlen, eof = 0;
int replies = 0;
while(ptr < end)
{
pktlen = MYSQL_GET_PACKET_LEN(ptr) + 4;
if(PTR_IS_OK(ptr) || PTR_IS_ERR(ptr) || PTR_IS_LOCAL_INFILE(ptr))
{
replies++;
ptr += pktlen;
}
else
{
while(ptr < end && eof < 2)
{
pktlen = MYSQL_GET_PACKET_LEN(ptr) + 4;
if(PTR_IS_EOF(ptr) || PTR_IS_ERR(ptr)) eof++;
ptr += pktlen;
}
if(eof == 2) replies++;
eof = 0;
}
}
return replies;
}
int lenenc_length(uint8_t* ptr)
{
char val = *ptr;
if(val < 251)
return 1;
else if(val == 0xfc)
return 3;
else if(val == 0xfd)
return 4;
else
return 9;
}
uint16_t get_response_flags(uint8_t* datastart, bool ok_packet)
{
uint8_t* ptr = datastart;
uint16_t rval = 0;
int pktlen = gw_mysql_get_byte3(ptr);
ptr += 4;
if(ok_packet)
{
ptr += lenenc_length(ptr);
ptr += lenenc_length(ptr);
memcpy(&rval,ptr,sizeof(uint8_t)*2);
}
else
{
/** This is an EOF packet*/
ptr += 2;
memcpy(&rval,ptr,sizeof(uint8_t)*2);
}
return rval;
}
/**
* The clientReply entry point. This is passed the response buffer
* to which the filter should be applied. Once processed the
@ -956,7 +1048,9 @@ clientReply (FILTER* instance, void *session, GWBUF *reply)
bool route = false,mpkt;
GWBUF *complete = NULL;
unsigned char *ptr;
uint16_t flags = 0;
int min_eof = my_session->command != 0x04 ? 2 : 1;
int more_results = 0;
#ifdef SS_DEBUG
ptr = (unsigned char*) reply->start;
skygw_log_write(LOGFILE_TRACE,"Tee clientReply [%s] [%s] [%s]: %d",
@ -1008,26 +1102,28 @@ clientReply (FILTER* instance, void *session, GWBUF *reply)
{
my_session->waiting[branch] = false;
my_session->multipacket[branch] = false;
if(PTR_IS_OK(ptr))
{
flags = get_response_flags(ptr,true);
more_results = (flags & 0x08) && my_session->client_multistatement;
}
}
#ifdef SS_DEBUG
else
{
ss_dassert(PTR_IS_RESULTSET(ptr));
skygw_log_write_flush(LOGFILE_DEBUG,"tee.c: [%d] Waiting for a result set from %s session.",
my_session->d_id,
branch == PARENT?"parent":"child");
}
ss_dassert(PTR_IS_ERR(ptr) || PTR_IS_LOCAL_INFILE(ptr)||
PTR_IS_OK(ptr) || my_session->waiting[branch] ||
!my_session->multipacket);
#endif
}
if(my_session->waiting[branch])
{
eof = modutil_count_signal_packets(complete,my_session->use_ok,my_session->eof[branch] > 0);
eof = modutil_count_signal_packets(complete,my_session->use_ok,my_session->eof[branch] > 0,&more_results);
more_results &= my_session->client_multistatement;
my_session->eof[branch] += eof;
if(my_session->eof[branch] >= min_eof)
{
#ifdef SS_DEBUG
@ -1035,27 +1131,27 @@ clientReply (FILTER* instance, void *session, GWBUF *reply)
my_session->d_id,
branch == PARENT?"parent":"child");
#endif
ss_dassert(my_session->eof[branch] < 3)
my_session->waiting[branch] = false;
my_session->waiting[branch] = more_results;
if(more_results)
{
my_session->eof[branch] = 0;
}
}
}
if(branch == PARENT)
{
//ss_dassert(my_session->tee_replybuf == NULL);
my_session->tee_replybuf = gwbuf_append(my_session->tee_replybuf,complete);
}
else
{
if(complete)
gwbuf_free(complete);
gwbuf_free(complete);
}
my_session->replies[branch]++;
rc = 1;
mpkt = my_session->multipacket[PARENT] || my_session->multipacket[CHILD];
if(my_session->tee_replybuf != NULL)
{
@ -1074,16 +1170,10 @@ clientReply (FILTER* instance, void *session, GWBUF *reply)
if(my_session->waiting[PARENT])
{
route = true;
#ifdef SS_DEBUG
ss_dassert(my_session->replies[PARENT] < 2 ||
modutil_count_signal_packets(my_session->tee_replybuf,
my_session->use_ok,
my_session->eof[PARENT]) == 0);
skygw_log_write_flush(LOGFILE_DEBUG,"tee.c:[%d] Routing partial response set.",my_session->d_id);
#endif
}
else if(my_session->eof[PARENT] == min_eof &&
my_session->eof[CHILD] == min_eof)
else if(my_session->eof[PARENT] >= min_eof &&
my_session->eof[CHILD] >= min_eof)
{
route = true;
#ifdef SS_DEBUG
@ -1098,7 +1188,7 @@ clientReply (FILTER* instance, void *session, GWBUF *reply)
skygw_log_write_flush(LOGFILE_DEBUG,"tee.c:[%d] Routing single packet response.",my_session->d_id);
#endif
route = true;
}
}
}
if(route)
@ -1236,3 +1326,13 @@ int detect_loops(TEE_INSTANCE *instance,HASHTABLE* ht, SERVICE* service)
return false;
}
int internal_route(DCB* dcb)
{
GWBUF* buffer = dcb->dcb_readqueue;
/** This was set in the newSession function*/
TEE_SESSION* session = dcb->data;
return routeQuery((FILTER*)session->instance,session,buffer);
}

View File

@ -71,7 +71,7 @@ static void blr_log_header(logfile_id_t file, char *msg, uint8_t *ptr);
int
blr_file_init(ROUTER_INSTANCE *router)
{
char *ptr, path[1024], filename[1050];
char *ptr, path[1025], filename[1051];
int file_found, n = 1;
int root_len, i;
DIR *dirp;
@ -80,12 +80,12 @@ struct dirent *dp;
if (router->binlogdir == NULL)
{
strcpy(path, "/usr/local/skysql/MaxScale");
if ((ptr = getenv("MAXSCALE_HOME")) != NULL)
if ((ptr = getenv("MAXSCALE_HOME")) != NULL && strnlen(ptr,1025) < 1025)
{
strcpy(path, ptr);
strncpy(path, ptr,PATH_MAX);
}
strcat(path, "/");
strcat(path, router->service->name);
strncat(path, "/",1024);
strncat(path, router->service->name,1024);
if (access(path, R_OK) == -1)
mkdir(path, 0777);
@ -196,7 +196,7 @@ unsigned char magic[] = BINLOG_MAGIC;
fsync(fd);
close(router->binlog_fd);
spinlock_acquire(&router->binlog_lock);
strcpy(router->binlog_name, file);
strncpy(router->binlog_name, file,BINLOG_FNAMELEN);
router->binlog_position = 4; /* Initial position after the magic number */
spinlock_release(&router->binlog_lock);
router->binlog_fd = fd;
@ -230,7 +230,7 @@ int fd;
fsync(fd);
close(router->binlog_fd);
spinlock_acquire(&router->binlog_lock);
strcpy(router->binlog_name, file);
strncpy(router->binlog_name, file,BINLOG_FNAMELEN);
router->binlog_position = lseek(fd, 0L, SEEK_END);
spinlock_release(&router->binlog_lock);
router->binlog_fd = fd;
@ -290,7 +290,7 @@ blr_file_flush(ROUTER_INSTANCE *router)
BLFILE *
blr_open_binlog(ROUTER_INSTANCE *router, char *binlog)
{
char path[1024];
char path[1025];
BLFILE *file;
spinlock_acquire(&router->fileslock);
@ -310,14 +310,14 @@ BLFILE *file;
spinlock_release(&router->fileslock);
return NULL;
}
strcpy(file->binlogname, binlog);
strncpy(file->binlogname, binlog,BINLOG_FNAMELEN+1);
file->refcnt = 1;
file->cache = 0;
spinlock_init(&file->lock);
strcpy(path, router->binlogdir);
strcat(path, "/");
strcat(path, binlog);
strncpy(path, router->binlogdir,1024);
strncat(path, "/",1024);
strncat(path, binlog,1024);
if ((file->fd = open(path, O_RDONLY, 0666)) == -1)
{
@ -630,7 +630,7 @@ struct stat statb;
void
blr_cache_response(ROUTER_INSTANCE *router, char *response, GWBUF *buf)
{
char path[4096], *ptr;
char path[4097], *ptr;
int fd;
strcpy(path, "/usr/local/skysql/MaxScale");

View File

@ -1228,8 +1228,8 @@ MYSQL_session *auth_info;
if ((auth_info = calloc(1, sizeof(MYSQL_session))) == NULL)
return NULL;
strcpy(auth_info->user, username);
strcpy(auth_info->db, database);
strncpy(auth_info->user, username,MYSQL_USER_MAXLEN+1);
strncpy(auth_info->db, database,MYSQL_DATABASE_MAXLEN+1);
gw_sha1_str((const uint8_t *)password, strlen(password), auth_info->client_sha1);
return auth_info;

View File

@ -385,7 +385,9 @@ char *sql;
if (modutil_MySQL_Query(queue, &sql, &len, &residual))
{
sql = strndup(sql, len);
return maxinfo_execute_query(instance, session, sql);
int rc = maxinfo_execute_query(instance, session, sql);
free(sql);
return rc;
}
else
{

View File

@ -85,6 +85,7 @@ int len;
return;
sprintf(msg, "%s in query '%s'", desc, sql);
maxinfo_send_error(dcb, 1149, msg);
free(msg);
}
/**
@ -112,7 +113,7 @@ int len;
data[4] = 0xff; // Error indicator
data[5] = errcode & 0xff; // Error Code
data[6] = (errcode >> 8) & 0xff; // Error Code
strncpy((char *)&data[7], "#42000", 6);
strncpy((char *)&data[13], msg, strlen(msg)); // Error Message
memcpy(&data[7], "#42000", 6);
memcpy(&data[13], msg, strlen(msg)); // Error Message
dcb->func.write(dcb, pkt);
}

View File

@ -735,7 +735,7 @@ exec_select(DCB *dcb, MAXINFO_TREE *tree)
static int
maxinfo_pattern_match(char *pattern, char *str)
{
int anchor, len, trailing;
int anchor = 0, len, trailing;
char *fixed;
extern char *strcasestr();

View File

@ -100,6 +100,7 @@ MAXINFO_TREE *col, *table;
}
}
// Malformed show
free(text);
free_tree(tree);
*parse_error = PARSE_MALFORMED_SHOW;
return NULL;
@ -136,31 +137,35 @@ parse_column_list(char **ptr)
int token, lookahead;
char *text, *text2;
MAXINFO_TREE *tree = NULL;
MAXINFO_TREE * rval = NULL;
*ptr = fetch_token(*ptr, &token, &text);
*ptr = fetch_token(*ptr, &lookahead, &text2);
switch (token)
{
case LT_STRING:
free(text2);
switch (lookahead)
{
case LT_COMMA:
return make_tree_node(MAXOP_COLUMNS, text, NULL,
rval = make_tree_node(MAXOP_COLUMNS, text, NULL,
parse_column_list(ptr));
case LT_FROM:
return make_tree_node(MAXOP_COLUMNS, text, NULL,
rval = make_tree_node(MAXOP_COLUMNS, text, NULL,
NULL);
default:
break;
}
break;
case LT_STAR:
free(text);
free(text2);
if (lookahead != LT_FROM)
return make_tree_node(MAXOP_ALL_COLUMNS, NULL, NULL,
rval = make_tree_node(MAXOP_ALL_COLUMNS, NULL, NULL,
NULL);
break;
default:
break;
}
return NULL;
free(text);
free(text2);
return rval;
}
@ -180,6 +185,7 @@ MAXINFO_TREE *tree = NULL;
*ptr = fetch_token(*ptr, &token, &text);
if (token == LT_STRING)
return make_tree_node(MAXOP_TABLE, text, NULL, NULL);
free(text);
return NULL;
}

View File

@ -305,7 +305,7 @@ char* get_lenenc_str(void* data, int* len)
* Parses a response set to a SHOW DATABASES query and inserts them into the
* router client session's database hashtable. The name of the database is used
* as the key and the unique name of the server is the value. The function
* currently supports only result sets that span a single GWBUF.
* currently supports only result sets that span a single SQL packet.
* @param rses Router client session
* @param target Target server where the database is
* @param buf GWBUF containing the result set
@ -315,9 +315,9 @@ bool parse_showdb_response(ROUTER_CLIENT_SES* rses, char* target, GWBUF* buf)
{
bool rval = false;
unsigned char* ptr;
int more = 0;
if(PTR_IS_RESULTSET(((unsigned char*)buf->start)) &&
modutil_count_signal_packets(buf,0,0) == 2)
modutil_count_signal_packets(buf,0,0,&more) == 2)
{
ptr = (unsigned char*)buf->start;

View File

@ -334,9 +334,10 @@ parse_mapping_response(ROUTER_CLIENT_SES* rses, char* target, GWBUF* buf)
{
bool rval = false;
unsigned char* ptr;
int more = 0;
if(PTR_IS_RESULTSET(((unsigned char*)buf->start)) &&
modutil_count_signal_packets(buf,0,0) == 2)
modutil_count_signal_packets(buf,0,0,&more) == 2)
{
ptr = (char*)buf->start;
@ -2988,4 +2989,4 @@ reply_error:
}
retblock:
return succp;
}
}