diff --git a/Documentation/Getting-Started/Configuration-Guide.md b/Documentation/Getting-Started/Configuration-Guide.md index 99ab0615d..85f99bf8d 100644 --- a/Documentation/Getting-Started/Configuration-Guide.md +++ b/Documentation/Getting-Started/Configuration-Guide.md @@ -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 diff --git a/Documentation/Getting-Started/MariaDB-MaxScale-Installation-Guide.md b/Documentation/Getting-Started/MariaDB-MaxScale-Installation-Guide.md index 6964e11c3..d520e53b5 100644 --- a/Documentation/Getting-Started/MariaDB-MaxScale-Installation-Guide.md +++ b/Documentation/Getting-Started/MariaDB-MaxScale-Installation-Guide.md @@ -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. diff --git a/Documentation/Tutorials/Administration-Tutorial.md b/Documentation/Tutorials/Administration-Tutorial.md index db8d19573..90c311646 100644 --- a/Documentation/Tutorials/Administration-Tutorial.md +++ b/Documentation/Tutorials/Administration-Tutorial.md @@ -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 - -## 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" ``` - -## 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 ``` - ## 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. - ## 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. - ## What Clients Are Connected To MariaDB MaxScale To determine what client are currently connected to MariaDB MaxScale, you can @@ -189,7 +158,6 @@ maxadmin. $ ``` - ## 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. - ## 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. diff --git a/Documentation/check_links.sh b/Documentation/check_links.sh index 157e2dc81..99b71a79b 100755 --- a/Documentation/check_links.sh +++ b/Documentation/check_links.sh @@ -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" diff --git a/README.md b/README.md index 07520f6c7..6d2703b45 100644 --- a/README.md +++ b/README.md @@ -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 diff --git a/maxscale-system-test/CMakeLists.txt b/maxscale-system-test/CMakeLists.txt index 6430f64d1..2fa2d8ac8 100644 --- a/maxscale-system-test/CMakeLists.txt +++ b/maxscale-system-test/CMakeLists.txt @@ -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) diff --git a/maxscale-system-test/cnf/maxscale.cnf.template.mxs1961_standalone_rejoin b/maxscale-system-test/cnf/maxscale.cnf.template.mxs1961_standalone_rejoin new file mode 100644 index 000000000..e9bcac12c --- /dev/null +++ b/maxscale-system-test/cnf/maxscale.cnf.template.mxs1961_standalone_rejoin @@ -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 diff --git a/maxscale-system-test/mxs1961_standalone_rejoin.cpp b/maxscale-system-test/mxs1961_standalone_rejoin.cpp new file mode 100644 index 000000000..1a06e8154 --- /dev/null +++ b/maxscale-system-test/mxs1961_standalone_rejoin.cpp @@ -0,0 +1,143 @@ +/** + * MXS-1961: Standalone master loses master status + */ + +#include "testconnections.h" +#include + +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; +} diff --git a/server/core/config.cc b/server/core/config.cc index 9eef4d562..8f20633bf 100644 --- a/server/core/config.cc +++ b/server/core/config.cc @@ -29,6 +29,7 @@ #include #include #include +#include #include #include @@ -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 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 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; diff --git a/server/core/gateway.cc b/server/core/gateway.cc index e289df089..03a9a96aa 100644 --- a/server/core/gateway.cc +++ b/server/core/gateway.cc @@ -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 */ diff --git a/server/core/internal/config.h b/server/core/internal/config.h index 6a1cbc877..7060f38ec 100644 --- a/server/core/internal/config.h +++ b/server/core/internal/config.h @@ -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