Merge branch '2.2' into develop

This commit is contained in:
Markus Mäkelä 2018-07-12 19:38:40 +03:00
commit e2fb0093b1
No known key found for this signature in database
GPG Key ID: 72D48FCE664F7B19
11 changed files with 478 additions and 301 deletions

View File

@ -23,7 +23,7 @@ plugin modules that tailor the behavior of the program.
* [Monitor Modules](#monitor-modules)
* [Filter Modules](#filter-modules)
* [Encrypting Passwords](#encrypting-passwords)
* [Reloading Configuration](#reloading-configuration)
* [Runtime Configuration Changes](#runtime-configuration-changes)
* [Authentication](#authentication)
* [Error Reporting](#error-reporting)
@ -1170,7 +1170,8 @@ log with details about who tried to connect to MariaDB MaxScale and from where.
The connection_timeout parameter is used to disconnect sessions to MariaDB
MaxScale that have been idle for too long. The session timeouts are disabled by
default. To enable them, define the timeout in seconds in the service's
configuration section.
configuration section. A value of zero is interpreted as no timeout, the same
as if the parameter is not defined.
Example:
@ -1720,10 +1721,52 @@ password=61DD955512C39A4A8BC4BB1E5F116705
```
## Runtime Configuration Changes
Read the following documents for different methods of altering the MaxScale
configuration at runtime.
* MaxAdmin
* [Runtime Configuration Changes](../Reference/MaxAdmin.md#runtime-configuration-changes)
* MaxCtrl
* [`create`](../Reference/MaxCtrl.md#create)
* [`destroy`](../Reference/MaxCtrl.md#destroy)
* [`add`](../Reference/MaxCtrl.md#add)
* [`remove`](../Reference/MaxCtrl.md#remove)
* [`alter`](../Reference/MaxCtrl.md#alter)
* [REST API](../REST-API/API.md) documentation
All changes to the configuration are persisted as individual configuration files
in `/var/lib/maxscale/maxscale.cnf.d/`. These files are applied after the main
configuration file and all auxiliary configurations have been loaded. This means
that once runtime configurations have been made, they need to be incorporated
into the main configuration files.
### Backing Up Configuration Changes
The combination of configuration files can be done either manually
(e.g. `rsync`) or with the `maxscale --export-config=FILE` command line
option. See `maxscale --help` for more information about how to use the
`--export-config` flag.
For example, to export the current runtime configuration, run the following
command.
```
maxscale --export-config=/tmp/maxscale.cnf.combined
```
This will create the `/tmp/maxscale.cnf.combined` file and write the current
configuration into the it. This allows new MaxScale instances to be easily set
up without requiring copying of all runtime configuration files.
## Reloading Configuration
**Note:** This functionality has been deprecated. Use the MaxScale REST API or the
MaxAdmin `alter` commands to change configuration values at runtime.
**Note:** This functionality has been deprecated and should not be used.
---
The current MariaDB MaxScale configuration may be updated by editing the
configuration file and then forcing MariaDB MaxScale to reread the configuration

View File

@ -1,75 +1,14 @@
# MariaDB MaxScale Installation Guide
## First Steps With MariaDB MaxScale
## Normal Installation
In this introduction to MariaDB MaxScale the aim is to take the reader
from the point of installation to making the decision as to which of
the various setups that are possible with MariaDB MaxScale should be
the initial configuration to use. One of the problems that new users to
MariaDB MaxScale suffer is deciding exactly what they should consider
as a base configuration to start exploring what MariaDB MaxScale
is capable of. MariaDB MaxScale is highly configurable,
with new plugins expanding the capabilities of MariaDB MaxScale,
whilst this makes it a very adaptable tool it does lead to an initial
hurdle in configuring MariaDB MaxScale.
Download the MaxScale package from the MariaDB Downloads page:
## Installation
* [https://mariadb.com/downloads/mariadb-tx/maxscale](https://mariadb.com/downloads/mariadb-tx/maxscale)
MariaDB MaxScale can be installed either using the MariaDB Enterprise Repository
or directly from a downloaded package.
### Using the MariaDB Enterprise Repository
* Go to [https://mariadb.com/my_portal/download](https://mariadb.com/my_portal/download).
* Sign in or create an account for you.
* Select your operating system and follow the instructions.
### From a Downloaded Package
The MaxScale package can be downloaded from the following locations:
* [https://mariadb.com/my_portal/download/maxscale](https://mariadb.com/my_portal/download/maxscale)
* [https://mariadb.com/downloads/maxscale](https://mariadb.com/downloads/maxscale)
Select your operating system and download the package.
Depending on your OS, the package will either be a _deb_ or an _rpm_.
An _rpm_ is installed as follows
```
$ sudo yum install path-to-maxscale-package.rpm
```
and a _deb_ as follows
```
$ sudo dpkg -i path-to-maxscale-package.deb
$ sudo apt-get install -f
```
### Starting MariaDB MaxScale
Before starting MariaDB MaxScale, you need to create a configuration file for it;
please see further [down](#configuring-mariadb-maxscale).
Once a configuration file has been created you can start MariaDB MaxScale:
```
systemctl start maxscale.service
```
If your system does not support systemd you can start MariaDB MaxScale using the
installed init.d script.
```
service maxscale start
```
Starting with version 2.0.3, MaxScale also supports Upstart.
An example configuration file is installed into the `/etc/` folder.
This file should be changed according to your needs.
Select your operating system and download the package. You can also use
[the MariaDB package repository](https://mariadb.com/kb/en/library/mariadb-package-repository-setup-and-usage/)
to install MaxScale.
## Install MariaDB MaxScale Using a Tarball
@ -87,90 +26,13 @@ To do this, refer to the separate document
## Configuring MariaDB MaxScale
The first step in configuring your MariaDB MaxScale is to determine
what it is you want to achieve with your MariaDB MaxScale and what environment
it will run in. The later is probably the easiest starting point for choosing
which configuration route you wish to take.
There are two distinct database environments which the first GA release
of MariaDB MaxScale supports; MariaDB Master/Slave Replication clusters and Galera Cluster.
[The MaxScale Tutorial](../Tutorials/MaxScale-Tutorial.md) covers the first
steps in configuring your MariaDB MaxScale installation. Follow this tutorial
to learn how to configure and start using MaxScale.
For more details, refer to the [Configuration Guide](Configuration-Guide.md).
### Master/Slave Replication Clusters
There are two major configuration options available to use MariaDB MaxScale
with a MariaDB Replication cluster; connection routing with separate read and
write connections, or read/write splitting with a single connection.
A separate tutorial is available for each of these configurations that
describes how to build the configuration file for MariaDB MaxScale that
will work with your environment.
Using a MariaDB Master/Slave Replication cluster will provide one node server
within the cluster that is the master server and the remainder of the servers
will be slaves. The slaves are read replicas of the master.
In a replication cluster like this all write operations must be performed
on the master.
This can provide not just added security of your data, but also read scalability.
In an application environment with a substantial proportions of read operations,
directing those read operations to the slave servers can increase
the total load which the system can handle by offloading the master server
from the burden of these read operations.
Making the choice between these two setups is relatively simple,
if you have an application that understands that there are some database servers
that it can only read from and one it must send all of the writes to,
then the connection routing option can be used.
Applications that are not written to separate read and write statements must use
a service within MariaDB MaxScale that will split the incoming stream of SQL statements
into operations that can be executed on the master and those that can be set to the slave.
These applications should use the statement based routing provided by
the Read/Write Splitter router.
### Galera Cluster
A Galera Cluster provides a true multi-master cluster option for MariaDB and MySQL
database environments. In such a setup any node that is part of the cluster
can be used to both execute read and write operations.
MariaDB MaxScale again offers two different configurations that can be used with Galera;
a connection balancing configuration or a statement splitting mechanism that can be used
to isolate write operations to a single node within the cluster.
Again there is a tutorial guide available for both of these major configurations.
The connection based load balancing configuration is used in an environment in which
you have a cluster that you want to be available to an application without
the application needing to be aware of the cluster configuration or state of
the database nodes.
MariaDB MaxScale will monitor the nodes within the database cluster and will
route connections from the application to database nodes that
are active members of the cluster.
MariaDB MaxScale will also keep track of the number of connections to each
database node keep equal numbers of connections to each node,
at the time the connection is established.
It is also possible to use the Read/Write Splitter with Galera.
Although it is not necessary to segregate the write operations to a single node,
there are advantages in doing this if you have an application where the write load
is not too great to be handled by a single node in the cluster.
Galera Cluster uses an optimistic locking strategy that will allow transactions
to progress independently on each node within the cluster.
It is only when the transaction commits that the transaction is checked for conflicts
with other transactions that are committing on the other nodes.
At this stage the commit can fail with a deadlock detection error.
This can be inconvenient for applications and, some older applications,
that are not aware that the transaction can fail at this stage
may not check for this failure.
Using the Read/Write Splitter will allow this to be avoided since
it will isolate the write to one node and no deadlock detection will occur.
MariaDB MaxScale provides a monitoring module that will maintain pseudo states
of master and slave for the Galera cluster that allows for this type of configuration.
### Other MariaDB MaxScale Configuration
As well as the four major configuration choices outlined above there are also other
configurations sub-options that may be mixed with those to provide a variety of different
configuration and functionality. The MariaDB MaxScale filter concept allows the basic configurations
to be built upon in a large variety of ways. A separate filter tutorial is available
that discusses the concept and gives some examples of ways to use filters.
For a detailed list of all configuration parameters, refer to the
[Configuration Guide](Configuration-Guide.md) and the module specific documents
listed in the [Documentation Contents](../Documentation-Contents.md#routers).
## Encrypting Passwords
@ -178,30 +40,13 @@ Read the [Encrypting Passwords](Configuration-Guide.md#encrypting-passwords)
section of the configuration guide to set up password encryption for the
configuration file.
## Running MariaDB MaxScale
MariaDB MaxScale consists of a core executable and a number of modules that implement
the different protocols and routing algorithms. These modules are built as
shared objects that are loaded on demand. In order for MariaDB MaxScale to find these
modules it will search using a configurable search path. The priority of these paths are:
1. Look in the directory defined with --libdir=PATH during startup
2. Look in the directory defined with libdir=PATH in the configuration file under the [maxscale] section
3. Look in default directory in /usr/lib64/maxscale
Configuration is read by default from the file /etc/maxscale.cnf. An example file is
included in in the installation and can be found in the /usr/share/maxscale folder within
the MariaDB MaxScale installation. The -f flag can be used on the command line to set
the name and the location of the configuration file. The -C flag can be used to set
the directory where the configuration file is searched for. Without the -f or -C flags,
the file is read from the /etc directory.
## Administration Of MariaDB MaxScale
There are various administration tasks that may be done with MariaDB MaxScale,
a client command, maxadmin, is available that will interact with a running
There are various administration tasks that may be done with MariaDB MaxScale.
Two command line tools are available, `maxctrl` and `maxadmin`, that will interact with a running
MariaDB MaxScale and allow the status of MariaDB MaxScale to be monitored and
give some control of the MariaDB MaxScale functionality.
There is [a separate reference guide](../Reference/MaxAdmin.md) for the maxadmin utility
and also [a short administration tutorial](../Tutorials/Administration-Tutorial.md)
that covers the common administration tasks that need to be done with MariaDB MaxScale.
There are a separate reference guides for the [maxctrl](../Reference/MaxCtrl.md) and [maxadmin](../Reference/MaxAdmin.md) utilities.
[The administration tutorial](../Tutorials/Administration-Tutorial.md)
covers the common administration tasks that need to be done with MariaDB MaxScale.

View File

@ -5,41 +5,37 @@ to a few of the common administration tasks. This is intended to be an
introduction for administrators who are new to MariaDB MaxScale and not a
reference to all the tasks that may be performed.
- [Starting MariaDB MaxScale](#starting)
- [Stopping MariaDB MaxScale](#stopping)
- [Checking The Status Of The MariaDB MaxScale Services](#checking)
- [Persistent Connections](#persistent)
- [What Clients Are Connected To MariaDB MaxScale](#clients)
- [Rotating the Log File](#rotating)
- [Taking A Database Server Out Of Use](#outofuse)
## Starting and Stopping MariaDB MaxScale
<a name="starting"></a>
## Starting MariaDB MaxScale
### Systemd
There are several ways to start MariaDB MaxScale, the most convenient mechanism
is probably using the Linux service interface. When a MariaDB MaxScale package
is installed, the package manager will also install a script in /etc/init.d
which may be used to start and stop MariaDB MaxScale either directly or via the
service interface.
Most modern operating systems support the Systemd interface.
**Starting MaxScale:**
```
$ service maxscale start
systemctl start maxscale
```
or
**Stopping MaxScale:**
```
$ /etc/init.d/maxscale start
systemctl stop maxscale
```
It is also possible to start MariaDB MaxScale by executing the maxscale command
itself. Running the executable /usr/bin/maxscale will result in MariaDB MaxScale
running as a daemon process, unattached to the terminal in which it was started
and using configuration files that it finds in the /etc directory.
The MaxScale service file is located in `/lib/systemd/system/maxscale.service`.
Options may be passed to the MariaDB MaxScale binary that alter this default
behavior. For a full list of all parameters, refer to the MariaDB MaxScale help
output by executing `maxscale --help`.
### SysV
Legacy platforms should use the service interface to start MaxScale.
**Starting MaxScale:**
```
service maxscale start
```
**Stopping MaxScale:**
```
service maxscale stop
```
Additional command line arguments can be passed to MariaDB MaxScale with a
configuration file placed at `/etc/sysconfig/maxscale` on RPM installations and
@ -51,43 +47,18 @@ quotes. The file should only contain environment variable declarations.
MAXSCALE_OPTIONS="--logdir=/home/maxscale/logs --piddir=/tmp --syslog=no"
```
<a name="stopping"></a>
## Stopping MariaDB MaxScale
Note that this is only supported on legacy SysV systems.
There are numerous ways in which MariaDB MaxScale can be stopped; using the
service interface, killing the process or by using the maxadmin utility.
Stopping MariaDB MaxScale with the service interface is simply a case of using
the service stop command or calling the init.d script with the stop argument.
```
$ service maxscale stop
```
or
```
$ /etc/init.d/maxscale stop
```
MariaDB MaxScale will also stop gracefully if it received a terminate signal, to
find the process id of the MariaDB MaxScale server use the ps command or read
the contents of the maxscale.pid file located in the /var/run/maxscale
directory.
```
$ kill `cat /var/run/maxscale/maxscale.pid`
```
## Stopping MariaDB MaxScale via MaxAdmin
In order to shutdown MariaDB MaxScale using the maxadmin command you may either
connect with maxadmin in interactive mode or pass the "shutdown maxscale"
command you wish to execute as an argument to maxadmin.
```
$ maxadmin shutdown maxscale
sudo maxadmin shutdown maxscale
```
<a name="checking"></a>
## Checking The Status Of The MariaDB MaxScale Services
It is possible to use the maxadmin command to obtain statistics about the
@ -122,7 +93,6 @@ Network listeners count as a user of the service, therefore there will always be
one user per network port in which the service listens. More details can be
obtained by using the "show service" command.
<a name="persistent"></a>
## Persistent Connections
When clients who are accessing a database system through MariaDB MaxScale make
@ -162,7 +132,6 @@ the desired configuration. In exceptional cases this feature could be a problem.
It is possible to have pools for as many servers as you wish, with configuration
values in each server section.
<a name="clients"></a>
## What Clients Are Connected To MariaDB MaxScale
To determine what client are currently connected to MariaDB MaxScale, you can
@ -189,7 +158,6 @@ maxadmin.
$
```
<a name="rotating"></a>
## Rotating the Log File
MariaDB MaxScale logs messages of different priority into a single log file.
@ -206,20 +174,12 @@ Log file rotation is achieved by use of the "flush log" or “flush logs” comm
in maxadmin.
```
$ maxadmin flush logs
maxadmin flush logs
```
As there currently is only the maxscale log, that is the only one that will be
rotated.
The maxscale log can also be flushed explicitly.
```
$ maxadmin
MaxScale> flush log maxscale
MaxScale>
```
This may be integrated into the Linux _logrotate_ mechanism by adding a
configuration file to the /etc/logrotate.d directory. If we assume we want to
rotate the log files once per month and wish to keep 5 log files worth of
@ -266,14 +226,13 @@ endscript
}
```
Since MaxScale currently renames the log file, the behaviour is not fully
In older versions MaxScale renamed the log file, behaviour which is not fully
compliant with the assumptions of logrotate and may lead to issues, depending on
the used logrotate configuration file. From version 2.1 onwards, MaxScale will
not itself rename the log file, but when the log is rotated, MaxScale will
simply close and reopen (and truncate) the same log file. That will make the
behaviour fully compliant with logrotate.
<a name="outofuse"></a>
## Taking A Database Server Out Of Use
MariaDB MaxScale supports the concept of maintenance mode for servers within a
@ -286,8 +245,7 @@ may be done interactively within maxadmin or by passing the command on the
command line.
```
MaxScale> set server dbserver3 maintenance
MaxScale>
sudo maxadmin set server dbserver3 maintenance
```
This will cause MariaDB MaxScale to stop routing any new requests to the server,
@ -298,14 +256,8 @@ To bring the server back into service use the "clear server" command to clear
the maintenance mode bit for that server.
```
MaxScale> clear server dbserver3 maintenance
MaxScale>
sudo maxadmin clear server dbserver3 maintenance
```
Note that maintenance mode is not persistent, if MariaDB MaxScale restarts when
a node is in maintenance mode a new instance of MariaDB MaxScale will not honor
this mode. If multiple MariaDB MaxScale instances are configured to use the node
them maintenance mode must be set within each MariaDB MaxScale instance. However
if multiple services within one MariaDB MaxScale instance are using the server
then you only need set the maintenance mode once on the server for all services
to take note of the mode change.
If multiple MariaDB MaxScale instances are configured to use the node
them maintenance mode must be set within each MariaDB MaxScale instance.

View File

@ -16,9 +16,8 @@
homedir=$(pwd)
find . -name '*.md'|while read file
do
cd "$(dirname "$file")"
function check_file() {
file=$1
grep -o '\[.*\]([^#].*[.]md)' "$(basename "$file")"| sed -e 's/\[.*\](\(.*\))/\1/'|while read i
do
if [ ! -f "$i" ]
@ -26,5 +25,15 @@ do
echo "Link $i in $file is not correct!"
fi
done
}
find . -name '*.md'|while read file
do
cd "$(dirname "$file")"
check_file $file
cd "$homedir"
done
cd ..
check_file $PWD/README.md
cd "$homedir"

View File

@ -12,18 +12,8 @@ functionality transparently to the applications. In addition it provides
a highly scalable and flexible architecture, with plugin components to
support different protocols and routing decisions.
MaxScale is implemented in C and makes extensive use of the
asynchronous I/O capabilities of the Linux operating system. The epoll
system is used to provide the event driven framework for the input and
output via sockets.
The protocols are implemented as external shared object modules which
can be loaded at runtime. These modules support a fixed interface,
communicating the entries points via a structure consisting of a set of
function pointers. This structure is called the "module object".
The code that routes the queries to the database servers is also loaded
as external shared objects and are referred to as routing modules.
For a detailed overview of what MaxScale can do, read the
[MaxScale page on the MariaDB website](https://mariadb.com/products/technology/maxscale).
An Google Group exists for MaxScale that can be used to discuss ideas,
issues and communicate with the MaxScale community.
@ -35,18 +25,27 @@ We're also on the #maria and #maxscale channels on FreeNode.
Please report all feature requests, improvements and bugs in the [MariaDB Jira](https://jira.mariadb.org/projects/MXS/issues).
# Getting Started
Read the [Documentation Overview](Documentation/Documentation-Contents.md) for a
list of all MaxScale documents.
- [Installing MaxScale](Documentation/Getting-Started/MariaDB-MaxScale-Installation-Guide.md)
- [Setting up MariaDB MaxScale](Documentation/Tutorials/MaxScale-Tutorial.md)
- [Building from Source Code](Documentation/Getting-Started/Building-MaxScale-from-Source-Code.md)
- [Other Tutorials](Documentation/Documentation-Contents.md#tutorials)
# Documentation
For information about installing and using MaxScale, please refer to the
documentation. The official documentation can be found on the
The official documentation can be found on the
[MariaDB Knowledge Base](https://mariadb.com/kb/en/mariadb-enterprise/maxscale/).
- [MariaDB MaxScale 2.1 Documentation](https://mariadb.com/kb/en/mariadb-enterprise/6308/)
- [MariaDB MaxScale 2.0 Documentation](https://mariadb.com/kb/en/mariadb-enterprise/mariadb-maxscale-20-contents/)
- [MariaDB MaxScale 1.4 Documentation](https://mariadb.com/kb/en/mariadb-enterprise/mariadb-maxscale-14/maxscale-maxscale-contents/)
A MaxScale Troubleshooting Guide can be found on the MariaDB Knowledgebase. It
answers common questions encountered when installing and using MaxScale.
The module and configuration documentation can be found in the _Documentation_
directory of the source tree.
The documentation can also be found in the
[Documentation](Documentation/Documentation-Contents.md) directory of the
source tree.
# Contributing Code

View File

@ -1029,11 +1029,17 @@ add_test_executable(mxs1949_warn_user_injection.cpp mxs1949_warn_user_injection
# MXS-1958: Users with insert-only privileges don't work
# https://jira.mariadb.org/browse/MXS-1958
add_test_executable(mxs1958_insert_priv.cpp mxs1958_insert_priv replication LABELS REPL_BACKEND)
# TODO: Remove this once MXS-1958 is fixed
set_tests_properties(mxs1958_insert_priv PROPERTIES WILL_FAIL TRUE)
# MXS-1849: Table family sharding router
# https://jira.mariadb.org/browse/MXS-1849
add_test_executable(mxs1849_table_sharding.cpp mxs1849_table_sharding mxs1849_table_sharding LABELS schemarouter BREAKS_REPL)
# MXS-1961: Standalone master loses master status
# https://jira.mariadb.org/browse/MXS-1961
add_test_executable(mxs1961_standalone_rejoin.cpp mxs1961_standalone_rejoin mxs1961_standalone_rejoin LABELS REPL_BACKEND)
configure_file(templates.h.in templates.h @ONLY)
include(CTest)

View File

@ -0,0 +1,60 @@
[maxscale]
threads=###threads###
[MySQL-Monitor]
type=monitor
module=mysqlmon
servers= server1, server2, server3
user=maxskysql
passwd= skysql
monitor_interval=1000
detect_standalone_master=true
failcount=1
allow_cluster_recovery=true
auto_failover=true
auto_rejoin=true
replication_user=repl
replication_password=repl
enforce_read_only_slaves=1
verify_master_failure=false
[RW Split Router]
type=service
router= readwritesplit
servers=server1, server2, server3
user=maxskysql
passwd=skysql
[RW Split Listener]
type=listener
service=RW Split Router
protocol=MySQLClient
port=4006
[CLI]
type=service
router=cli
[CLI Listener]
type=listener
service=CLI
protocol=maxscaled
socket=default
[server1]
type=server
address=###node_server_IP_1###
port=###node_server_port_1###
protocol=MySQLBackend
[server2]
type=server
address=###node_server_IP_2###
port=###node_server_port_2###
protocol=MySQLBackend
[server3]
type=server
address=###node_server_IP_3###
port=###node_server_port_3###
protocol=MySQLBackend

View File

@ -0,0 +1,143 @@
/**
* MXS-1961: Standalone master loses master status
*/
#include "testconnections.h"
#include <iostream>
using namespace std;
void checkpoint(TestConnections& test)
{
const int v = 5;
test.maxscales->wait_for_monitor(v);
for (auto&& s: {"server1", "server2", "server3"})
{
auto status = test.get_server_status(s);
cout << s << " { ";
for (auto a: status)
{
cout << a << ", ";
}
cout << "}\n";
}
}
int main(int argc, char *argv[])
{
Mariadb_nodes::require_gtid(true);
TestConnections test(argc, argv);
auto status = [&](const char* server)
{
return test.get_server_status(server);
};
auto comment = [&](const char* comment)
{
cout << comment << endl;
test.maxscales->ssh_node_f(0, true, "echo '----- %s -----' >> /var/log/maxscale/maxscale.log", comment);
};
auto slave = [&](const char* name)
{
static StringSet slave{"Slave", "Running"};
test.assert(status(name) == slave, "'%s' should be a slave", name);
};
auto master = [&](const char* name)
{
static StringSet master{"Master", "Running"};
test.assert(status(name) == master, "'%s' should be the master", name);
};
auto down = [&](const char* name)
{
static StringSet down{"Down"};
test.assert(status(name) == down, "'%s' should be down", name);
};
auto block = [&](int node)
{
test.repl->block_node(node);
checkpoint(test);
};
auto unblock = [&](int node)
{
test.repl->unblock_node(node);
checkpoint(test);
};
test.maxscales->wait_for_monitor(1);
master("server1");
slave("server2");
slave("server3");
comment("Blocking server1");
block(0);
comment("Blocking server2");
block(1);
down("server1");
down("server2");
master("server3");
comment("Unblocking server2");
unblock(1);
down("server1");
slave("server2");
master("server3");
comment("Blocking server3");
block(2);
comment("Unblocking server3");
unblock(2);
down("server1");
master("server2");
slave("server3");
comment("Blocking server3");
block(2);
down("server1");
master("server2");
down("server3");
comment("Unblocking server1");
unblock(0);
slave("server1");
master("server2");
down("server3");
comment("Blocking server2");
block(1);
master("server1");
down("server2");
down("server3");
comment("Unblocking server2");
unblock(1);
master("server1");
slave("server2");
down("server3");
comment("Unblocking server3");
unblock(2);
master("server1");
slave("server2");
slave("server3");
test.maxscales->stop();
test.repl->fix_replication();
return test.global_result;
}

View File

@ -29,6 +29,7 @@
#include <ini.h>
#include <set>
#include <string>
#include <fstream>
#include <vector>
#include <maxscale/adminusers.h>
@ -221,6 +222,7 @@ static const char *config_file = NULL;
static MXS_CONFIG gateway;
char *version_string = NULL;
static bool is_persisted_config = false; /**< True if a persisted configuration file is being parsed */
static CONFIG_CONTEXT config_context;
const char *config_service_params[] =
{
@ -350,6 +352,17 @@ const char *deprecated_server_params[] =
NULL
};
void config_init()
{
config_context.object = (char*)"";
config_context.next = NULL;
}
void config_finish()
{
config_context_free(config_context.next);
}
/**
* Initialize the context object used for tracking duplicate sections.
*
@ -528,6 +541,11 @@ static bool is_empty_string(const char* str)
return true;
}
static bool is_maxscale_section(const char* section)
{
return strcasecmp(section, CN_GATEWAY) == 0 || strcasecmp(section, CN_MAXSCALE) == 0;
}
static bool is_root_config_file = true;
/**
@ -578,19 +596,7 @@ static int ini_handler(void *userdata, const char *section, const char *name, co
}
}
if (strcmp(section, CN_GATEWAY) == 0 || strcasecmp(section, CN_MAXSCALE) == 0)
{
if (is_root_config_file || is_persisted_config)
{
return handle_global_item(name, value);
}
else
{
MXS_ERROR("The [maxscale] section must only be defined in the root configuration file.");
return 0;
}
}
else if (strlen(section) == 0)
if (strlen(section) == 0)
{
MXS_ERROR("Parameter '%s=%s' declared outside a section.", name, value);
return 0;
@ -643,6 +649,19 @@ static int ini_handler(void *userdata, const char *section, const char *name, co
return 0;
}
if (is_maxscale_section(section))
{
if (is_root_config_file || is_persisted_config)
{
return handle_global_item(name, value);
}
else
{
MXS_ERROR("The [maxscale] section must only be defined in the root configuration file.");
return 0;
}
}
return 1;
}
@ -888,6 +907,59 @@ static bool contains_cnf_files(const char *path)
return rval;
}
bool export_config_file(const char* filename)
{
bool rval = true;
std::vector<CONFIG_CONTEXT*> contexts;
// The config objects are stored in reverse order so first convert it back
// to the correct order
for (CONFIG_CONTEXT* ctx = config_context.next; ctx; ctx = ctx->next)
{
contexts.push_back(ctx);
}
std::ofstream file(filename);
if (file)
{
time_t now = time(NULL);
file << "# Generated by MaxScale " << MAXSCALE_VERSION << '\n';
file << "# Documentation: https://mariadb.com/kb/en/mariadb-enterprise/maxscale/ \n\n";
for (auto it = contexts.rbegin(); it != contexts.rend(); it++)
{
CONFIG_CONTEXT* ctx = *it;
file << '[' << ctx->object << "]\n";
// Parameters are also stored in reverse order
std::vector<MXS_CONFIG_PARAMETER*> params;
for (MXS_CONFIG_PARAMETER* p = ctx->parameters; p; p = p->next)
{
params.push_back(p);
}
for (auto pit = params.rbegin(); pit != params.rend(); pit++)
{
MXS_CONFIG_PARAMETER* p = *pit;
file << p->name << '=' << p->value << '\n';
}
file << '\n';
}
}
else
{
MXS_ERROR("Failed to open configuration export file '%s': %d, %s",
filename, errno, mxs_strerror(errno));
rval = false;
}
return rval;
}
/**
* @brief Load the specified configuration file for MaxScale
*
@ -904,15 +976,11 @@ static bool
config_load_and_process(const char* filename, bool (*process_config)(CONFIG_CONTEXT*))
{
bool rval = false;
DUPLICATE_CONTEXT dcontext;
if (duplicate_context_init(&dcontext))
{
CONFIG_CONTEXT ccontext = {};
ccontext.object = (char*)"";
if (config_load_single_file(filename, &dcontext, &ccontext))
if (config_load_single_file(filename, &dcontext, &config_context))
{
is_root_config_file = false;
const char DIR_SUFFIX[] = ".d";
@ -925,7 +993,7 @@ config_load_and_process(const char* filename, bool (*process_config)(CONFIG_CONT
if (is_directory(dir))
{
rval = config_load_dir(dir, &dcontext, &ccontext);
rval = config_load_dir(dir, &dcontext, &config_context);
}
/** Create the persisted configuration directory if it doesn't exist */
@ -954,7 +1022,7 @@ config_load_and_process(const char* filename, bool (*process_config)(CONFIG_CONT
*/
if (duplicate_context_init(&p_dcontext))
{
rval = config_load_dir(persist_cnf, &p_dcontext, &ccontext);
rval = config_load_dir(persist_cnf, &p_dcontext, &config_context);
duplicate_context_finish(&p_dcontext);
}
else
@ -966,7 +1034,7 @@ config_load_and_process(const char* filename, bool (*process_config)(CONFIG_CONT
if (rval)
{
if (!check_config_objects(ccontext.next) || !process_config(ccontext.next))
if (!check_config_objects(config_context.next) || !process_config(config_context.next))
{
rval = false;
if (contains_cnf_files(persist_cnf))
@ -980,8 +1048,6 @@ config_load_and_process(const char* filename, bool (*process_config)(CONFIG_CONT
}
}
config_context_free(ccontext.next);
duplicate_context_finish(&dcontext);
}
return rval;
@ -1024,6 +1090,12 @@ process_config_context(CONFIG_CONTEXT *context)
obj = context;
while (obj)
{
if (is_maxscale_section(obj->object))
{
obj = obj->next;
continue;
}
char *type = config_get_value(obj->parameters, CN_TYPE);
if (type)
{
@ -1058,6 +1130,12 @@ process_config_context(CONFIG_CONTEXT *context)
obj = context;
while (obj)
{
if (is_maxscale_section(obj->object))
{
obj = obj->next;
continue;
}
char *type = config_get_value(obj->parameters, CN_TYPE);
if (type)
{
@ -2340,6 +2418,12 @@ check_config_objects(CONFIG_CONTEXT *context)
while (obj)
{
if (is_maxscale_section(obj->object))
{
obj = obj->next;
continue;
}
const char **param_set = NULL;
const char *module = NULL;
const char *type;

View File

@ -105,6 +105,7 @@ const char *progname = NULL;
static struct option long_options[] =
{
{"config-check", no_argument, 0, 'c'},
{"export-config", required_argument, 0, 'e'},
{"daemon", no_argument, 0, 'n'},
{"nodaemon", no_argument, 0, 'd'},
{"config", required_argument, 0, 'f'},
@ -948,6 +949,7 @@ static void usage(void)
fprintf(stderr,
"\nUsage : %s [OPTION]...\n\n"
" -c, --config-check validate configuration file and exit\n"
" -e, --export-config=FILE export configuration to a single file\n"
" -d, --nodaemon enable running in terminal process\n"
" -f, --config=FILE relative or absolute pathname of config file\n"
" -l, --log=[file|shm|stdout] log to file, shared memory or stdout\n"
@ -1334,7 +1336,9 @@ int main(int argc, char **argv)
bool pid_file_created = false;
Worker* worker;
const char* specified_user = NULL;
char export_cnf[PATH_MAX + 1] = "";
config_init();
config_set_global_defaults();
ss_dassert(cnf);
@ -1348,7 +1352,7 @@ int main(int argc, char **argv)
file_write_header(stderr);
// Option string for getopt
const char accepted_opts[] = "dncf:g:l:vVs:S:?L:D:C:B:U:A:P:G:N:E:F:M:H:p";
const char accepted_opts[] = "dnce:f:g:l:vVs:S:?L:D:C:B:U:A:P:G:N:E:F:M:H:p";
/*<
* Register functions which are called at exit.
@ -1654,6 +1658,11 @@ int main(int argc, char **argv)
cnf->config_check = true;
break;
case 'e':
cnf->config_check = true;
strcpy(export_cnf, optarg);
break;
case 'p':
cnf->passive = true;
break;
@ -2087,6 +2096,12 @@ int main(int argc, char **argv)
if (cnf->config_check)
{
MXS_NOTICE("Configuration was successfully verified.");
if (*export_cnf && export_config_file(export_cnf))
{
MXS_NOTICE("Configuration exported to '%s'", export_cnf);
}
rc = MAXSCALE_SHUTDOWN;
goto return_main;
}
@ -2231,6 +2246,8 @@ return_main:
MXS_FREE(cnf_file_path);
}
config_finish();
return rc;
} /*< End of main */

View File

@ -47,6 +47,16 @@ extern const char *config_filter_params[];
extern const char *config_server_params[];
extern const char *config_pre_parse_global_params[];
/**
* Initialize the configuration subsystem
*/
void config_init();
/**
* Finalize the configuration subsystem
*/
void config_finish();
/**
* Set the defaults for the global configuration options
*/
@ -174,4 +184,13 @@ void fix_section_name(char *section);
*/
bool config_global_serialize();
/**
* Export the configuration to a file
*
* @param filename Filename where the configuration will be written
*
* @return True if configuration was successfully exported
*/
bool export_config_file(const char* filename);
MXS_END_DECLS