MySQL-Sandbox-3.1.04/000755 000765 000024 00000000000 12631550766 014252 5ustar00gmaxstaff000000 000000 MySQL-Sandbox-3.1.04/bin/000755 000765 000024 00000000000 12631550766 015022 5ustar00gmaxstaff000000 000000 MySQL-Sandbox-3.1.04/Changelog000644 000765 000024 00000106765 12631531021 016062 0ustar00gmaxstaff000000 000000 3.1.04 07-Dec-2015 - Fixed wrong version comparison (affects usage of MySQL 5.7.10) - Changed tests to use smarter version comparison 3.1.03 04-Dec-2015 - Increased timeout for 'start' script, needed when restart requires a longer time. 3.1.02 21-Nov-2015 - Fixed error in UUID generation for server-id=110 - Merged change by Mark Leith to preserve mysql.sys user - Adapted privileges test for the above change 3.1.01 04-Oct-2015 - Removed message that should only appear with debug - Modified Makefile.PL to generate correct licensing metadata - Added port info to replication status and check-slaves (Thanks to Mark Leith) - Changed 'create schema' to 'create' database to allow installation in MySQL 4.1 (thanks to Daniƫl van Eeden) - Updated sbtool to prevent deletion of the whole sandboxes directory - Minor changes to semi-sync plugin test - Added debug message in make_sandbox_from_source - Tested with MySQL 5.7.9 and MariaDB 10.1.6 3.1.00 22-Aug-2015 - Migrated repository to github (github.com/datacharmer/mysql-sandbox) - Changed license to Apache 2.0 - Limited workaround for bug#77732 to MySQL 5.7.8 only - Added usability feature for Server-UUID. Whenever server-id is used, the server-uuid is converted into an easy-to-read string of numbers - Simplified './clear' script. Does not attempt to remove stored routines. Makes the intrusive mysqldump that was running with load_grants unnecessary - Changed location for MySQL history in group sandboxes to be shared between single ones. 3.0.66 07-Aug-2015 - Added MYSQL_EDITOR variable to ./use script - Added ./mycli script to invoke the mycli command 3.0.65 06-Aug-2015 - Added show_relaylog script, similar to show_binlog 3.0.64 05-Aug-2015 - Fixed quoting error in show_binlog script 3.0.63 04-Aug-2015 - Modified test add_option.sb.pl so that it can also run on MySQL 5.0 - modified sandbox script json_in_db to use type JSON when version >= 5.7.8 - Simplified grants.mysql and show_binlogs scripts 3.0.62 02-Aug-2015 - Added default name for relay log files. - Added 'show_binlog' and 'add_option' scripts in each sandbox - improved tests by getting all the version components from a single function call - Added GTID initialization options for MySQL 5.6, 5.7, and MariaDB 10 - Added GTID enabling test for MySQL 5.6 and 5.7 - added and improved more tests 3.0.61 27-Jul-2015 - Simplified workaround for Bug#77732. No defaults are changed. The only addition is a GRANT SELECT on a given table to the replication user for MySQL 5.7.6+ - Removed unnecessary FLUSH PRIVILEGES 3.0.60 25-Jul-2015 - Changed installation method for MySQL 5.7.6 and later. Using 'mysqld --initialize' instead of deprecated mysql_install_db. Installation for earlier MySQL versions and MariaDB still use mysql_install_db. - Due to the above change, low_level_make_sandbox will now filter the "error" message in the output for the text '[Warning]'. If an "error" appears as warning, the installation is not halted. - Incompatible change: when using --force to install on top of an existing sandbox, the old data directory is copied to 'old_data' instead of being overwritten. This is due to the different behavior of 'mysqld --initialize' that does not support initializing an existing data directory. - Added more tests. Improved a few of the existing ones. - Fixed test for user privileges that was broken in 5.7.6+ 3.0.57 to 3.0.59 not released 3.0.56 20-Jul-2015 - Adjusted credis date 3.0.55 19-Jul-2015 - Fixed issue with the latest script added to the test suite. 3.0.54 19-Jul-2015 - Added test_replication script to test both regular and circular replication. It is also used in the test suite 3.0.53 16-Jul-2015 - Improved workaround for Bug#77732. Deployments with --master would only work within the test suite, but would fail in standalone installations. 3.0.52 15-Jul-2015 - Added a workaround for Bug#77732 in MySQL 5.7.8 -- https://bugs.mysql.com/bug.php?id=77732 -- 3.0.51 14-Jul-2015 - Added ability of opening tarball with name like 123456.mysql*.tar.gz - Added many tests for tarball name checking 3.0.50 11-Apr-2015 - Fixed issue with the 'clear' script in MySQL 5.7.7. Since a new default database was added ('sys') and the clear command did not know about it, the new database was being removed. 3.0.49 08-Apr-2015 - Fixed version detection to support also MySLQL 5.7.7 and MySQL 5.7.8. A more resilient patch will follow. Notice that, due to a change (possibly a bug) in MySQL 5.7.7, circular replication and in general any topology containing a relay slave may fail. 3.0.48 09-Mar-2015 - Added provisional support for MySQL 5.7.6 (changed syntax for SET PASSWORD but keep using deprecated mysql_install_db) 3.0.47 19-Oct-2014 - Added support for MySQL with data dictionary (5.7.5 labs edition) 3.0.46 25-Sep-2014 - Modified smoke test in test_sandbox to check correctly older and newer versions - Changes to allow installation of MySQL 5.7.5: - added creation of 'test' database - moved lower_case_table_names to the my.sandbox.cnf file (mysql_install_db does not support this option) - allow for changed syntax --insecure instead of --skip-random-password - removed tmpdir from options to mysql_install_db - Updated test_sandbox to avoid a 'skip-innodb' test with MariaDB 10.x - Updated test_sandbox to detect correctly MariaDB versions 3.0.45 30-Aug-2014 - Fixing bug#1361851 "start/stop/status scripts don't actually check if running" - Fixing freshly submitted but long overdue Bug#1362014 "Sandbox scripts can't deal with stale PID files" 3.0.44 29-Apr-2014 - Fixing bug#1313672 : MySQL Sandbox can't install with MySQL 5.7.4 - Removed some deprecated options that were removed in latest version of MySQL 3.0.43 24-Oct-2013 - Fixed bug#1155517 The "my" scripts excludes mysql_upgrade from --default-options incorrectly - Also added mysql_config_editor to the scripts that should not get defaults-options 3.0.42 30-Sep-2013 - Fixed bug in sb renaming. The new name was not updated in the MANIFEST 3.0.41 30-Sep-2013 - INCOMPATIBLE CHANGE: Renamed 'sb' to 'msb' to avoid name clashes in - INCOMPATIBLE CHANGE: Renamed 'sb' to 'msb' to avoid name clashes in Linux distributions 3.0.40 12-Jul-2013 - enhanced deploy_to_remote_sandboxes.sh with the ability of using a template my.cnf for remote deployment (-y file-name) 3.0.39 29-May-2013 - added server_id option to deploy_to_remote_sandboxes - added info about group directory to multiple sandbox 'start/stop/clear' scripts - added ruby connection info to connection.json - Fixed display bug in credits (were reported twice in replication README) 3.0.38 05-May-2013 - Fixed typos and formatting in embedded docs. 3.0.37 05-May-2013 - Added connection samples (for PHP, Perl, Python, Java, shell) to 'connection.json' - Added validation tests for JSON contents 3.0.36 04-May-2013 - IMPORTANT CHANGES: - Added connection.json to each sandbox (simple or multiple) The file contains information to use the sandbox with third party applications. - Added default_connection.json to each sandbox (it has only the default items from connection.json) - Added README file to each sandbox (simple or multiple) - enhanced check_slaves. It now includes "show master status"; - Fixed bug in circular replication: enable_gtid was not created; - Added 25 more integrity tests; - Changed default version for testing. It now looks for MySQL 5.5.31 3.0.35 03-May-2013 - Fixed bug in the 'check_slaves' script created with circular replication - Fixed bug in 'clear_all' script created in circular replication - added 50 new integrity tests to test_sandbox 3.0.34 29-Apr-2013 - Added option --bind_address, to define how MySQL::Sandbox servers connect to TCP/IP - Fixed bug with handling 5.7 builds. Replicated systems did not create the script enable_gtid (BUG#1171977) - The changes made by enable_gtid are now durable (Bug#1171986) - Fixed various patterns that prevented MariaDB 10.0 builds from being recognized. - Fixed bug in test_sandbox, where warning messages were mixed with the test output in MYSQL 5.5.30+ - Fixed bug in test_sandbox, where a test that skips innodb was being wrongly applied to MySQL 5.7 - Added 10.0 among supported versions - Added documentation about remote sandboxes (in MySQL::Sandbox::Recipes) - Added a test that checks if enable_gtid is created when needed. 3.0.33 11-Apr-2013 - Fixed Bug #1167794 '--log option deprecated' - fixed minot working issue in deploy_to_remote_sandboxes.sh 3.0.32 12-Mar-2013 - Fixed minor bug in deploy_to_remote_sandboxes.sh - Added deploy_to_remote_sandboxes.sh to the list of scripts to install 3.0.31 08-Mar-2013 - Fixed Bug#1133186 make_sandbox_from_source does not recognize version - removed diagnostic lines that printed MySQL version and temporary directory - removed diagnostic lines that printed ports and directories being searched when the option --check_port was used - added bin/deploy_to_remote_sandboxes.sh, which installs sandboxes to remote hosts 3.0.30 06-Feb-2013 - Fixed Bug#1116760 Uninitalized $ENV{"SANDBOX_BINARY"} - Removed obnoxious warning introduced in MySQL 5.5.30 when using mysqldump 3.0.29 24-Jan-2013 - fixed bug#1103918 (affects sandboxes using MySQL 4.1) 3.0.28 06-Jan-2013 - changed initialization scripts to avoid most of the annoying messages that MySQL 5.6 creates during tests - Added script to enable GTID in MySQL 5.6 3.0.27 05-Jan-2013 - added compatibility features to use MySQL 5.6 # improved 'clear' and 'start' scripts to handle innodb tables in the 'mysql' database # fixed usage of deprecated features in tests # removed obnoxious listing when data directory is created 3.0.26 30-Sep-2012 - Removed dependency on table mysql.host, which can't be found anymore in MySQL 5.6.7 3.0.25 01-Feb-2012 - fixed typos and credits. (Thanks to Mateusz Kijowski for noticing) 3.0.24 17-Dec-2011 - added --master option to low_level_make_sandbox (enables binlogs and server-ID) - added --slaveof option to low_level_make_sandbox (creates a slave of another sandbox or regular server) - added tests for the above ones 3.0.23 13-Dec-2011 - fixed bug in prefixed version names (e.g.: now you can use make_sandbox ps5.1.57 or mp5.2.10) - Added arguments to deal with node options in replication and multiple sandbox. --node_options, --slave_options, --master_options, --one_slave_options, --one_node_options - added --high_performance option to low_level_make_sandbox: adds the following features to the configuration file: innodb-thread-concurrency=0 sync_binlog=0 innodb-log-buffer-size=50M innodb-additional-mem-pool-size=100M max-connections=350 max_allowed_packet=48M innodb_buffer_pool_size=512M innodb-log-file-size=50M innodb-flush-method=O_DIRECT 3.0.22 26-Oct-2011 - Add support for directories named after a prefixed version (my5.1.56, ps5.1.56, giuseppe_5.1.56, etc) 3.0.21 10-Oct-2011 - Added test to MANIFEST (and to tarball). Forgotten in previous version 3.0.20 10-Oct-2011 - Fixed bug in make_sandbox. "--add_prefix" did not work in combination with "--export_binaries" - changed port checking tests to not depend on a specific MySQL version 3.0.19 09-Oct-2011 - INCOMPATIBLE CHANGE: make_sandbox now requires '--' before adding options supported by low_level_make_sandbox - INCOMPATIBLE CHANGE: the option --export_binaries for make_sandbox must be inserted BEFORE the tarball name - make_sandbox now recognizes Percona and MariaDB binaries - make_sandbox accepts the option --add_prefix=NAME, which will be added to the version number of the rename expanded tarball. (e.g. --add_prefix=yell mysql-5.1.8-linux.tar.gz will create yell5.1.58) 3.0.18 08-Oct-2011 - fixed CPAN Ticket 70470 MySQL::Sandbox - make_sandbox warns with Perl 5.14 and 5.14.1 - Fixed report-port in replication. The port used was the master's, but it should be the slave's 3.0.17 07-Jan-2011 - incompatible change: default mask for msandbox user is now '127.%' instead of '%'. You can resume the old mask with --remote_access='%' - added low privilege users msandbox_ro (SELECT EXECUTE), msandbox_rw (SELECT INSERT UPDATE CREATE DROP LOCK EXECUTE), and rsandbox (REPLICATION SLAVE) - fixed bug in test_smoke (assumed 2 directories after cleaning, but 5.5 has also performance_schema) 3.0.16 30-Dec-2010 - fixed bug in TestHelper (wrong assumption on all directories in $SANDBOX_BINARIES containing MySQL files) - added information to check_slaves to report master logfile and position 3.0.15 23-Dec-2010 - added a 'msb' script to each sandbox, to mimick the mysql.server script - fixed test visualization bug for Mac OSX with case insensitive storage - fixed algorithm to convert version number to ports - fixed test suite for MySQL 5.5 (can't disable innodb for testing) 3.0.14 31-Aug-2010 (not released) - Added a 'rsandbox' user with REPLICATION SLAVE grants for replication systems 3.0.13 28-Jun-2010 (not released) - fixed minor problems in the test suite about testing on Windows - added a prototype for MySQL Cluster integration 3.0.12 29-May-2010 - Fixed bug in test_sandbox. When a test evaluates only the result code and there is no output from a failing command, test_result was not able to detect the failure. - fixed bug in test_sandbox. Due to a change in behavior in the mysql client, where './use -B -N' with a \G terminated query does not show the headers since 5.1.43, We need to take into account the pre and post fix behaviors in the test. - Integrated set_plugins into sbtool - Updated documentation - added tests for innodb plugin installation - added tests for semi-synch plugin installation - Fixed bug in 'stop' script. It did not accept $MYCLIENT_OPTION - Fixed bug#487864 - tar was using '--help' instead of '--version' to detect the supported version. - Fixed bug in sbtool. It did not display credits in the help. - Added test to skip testing on Windows. - added instrumentation to all MySQL Sandbox scripts. If you set the $SBINSTR environment variable with the name of a file, all sandbox scripts will write an entry to that file with their run time params. 3.0.11 24-May-2010 - Fixed bug in ./clear script. In version 5.5 and bigger, it erased the performance_schema database, which should not be removed. If it exists, its tables are now truncated. - Fixed bug in ./clear script. The removal of databases was not executed in a clean mode. - Added a script to install plugins in ./drafts 3.0.10 04-May-2010 - Fixed the help() function. It displayed an example that was only appropriate for a single sandbox, but not for group ones. 3.0.09 25-Mar-2010 - added a check in the 'start' script to verify that mysqld_safe exists and can run properly. - Added an exit code to the 'start' script to alert when the server does not start - added help to make_sandbox_from_installed. Added /usr/sbin as source directory - added instructions to the 'clear' script to remove functions and plugins 3.0.08 17-Feb-2010 - Fixed make_sandbox_from_source failure due to changes in modified configure.in (Thanks to Padraig O'Sullivan for noticing) - modified the "USING" file, which now includes the Sandbox version - Changed default test version from 5.0.77 to 5.0.86 3.0.07 08-Jan-2010 - Fixed bud in make_multiple_custom_sandbox. With some versions of bash, it broke on tests with "use_all" - fixed bug on symlink access on some platforms. - Fixed Bug#504789 export_binaries fails on some OS when crossing file systems 3.0.06 03-Jan-2010 - Fixed bug in prompt definition. A stray quote was added at the start of each user-defined prompt. - Fixed Bug#456949 "each sandbox should have a dedicated temporary directory". - Fixed Bug#439226 "sandbox_action script uses wrong version of Perl" - Improved documentation to resolve Bug#392996 "make install Sandbox.pm path issues". - added 'status' script to sandboxes - fixed db_user definition, which could write trail character to the option file. 3.0.05 12-Sep-2009 - Fixed Bug#428274 make_sandbox fails on Mac OSX 10.6 "snow Leopard" - Increased starting timeout from 20 to 60, because some recent versions of MySQL are quite slower to start. - Added a dedicated history file per each sandbox (Thanks to Gerardo Narvaja for suggesting it) - fixed bug in make_sandbox when dealing with a non-standard answer to the "which" Unix utility - added error checking for 'bash' to low_level_make_sandbox - improved error checking for mysql_install_db script - renamed 'sandbox' tool -> 'msandbox' to prevent clash with existing tool in Linux distros - Added "--no_run" option to low_level_make_sandbox, to stop the server when using the "--load_grants" option. The purpose is to end the command without leaving any running sub-process. 3.0.04 14-Jun-2009 - fixed bug in test_sandbox. A "$" sign in a directory name was not escaped properly - added the "--no_show" option to low_level_make_sandbox - fixed a bug in the "sb" script. Calling it in "create mode" did fail if $SANDBOX_HOME does not exist yet. 3.0.03 11-Jun-2009 - added the 'sb' shortcut script to create and invoke sandboxes easily. 3.0.02 30-May-2009 - Added a check for all scripts, to prevent MySQL::Sandbox from running as root without explicit awareness 3.0.01 28-May-2009 - Fixed Bug#381044 "my" script fails on some executables - moved function "exists_in_path" to MySQL::Sandbox module 3.0.00 09-May-2009 - GA release - no code modification. Same codebase as 2.0.99f - completed cookbook (41 recipes in MySQL::Sandbox::Recipes) - added script_templates directory (No modification in current version, just preparation for 3.1.xx) - added drafts directory 2.0.99f 03-May-2009 - fixed bug in make_sandbox_from_installed. Some system use /lib64 instead of /lib - added more recipes to MySQL::Sandbox::Recipes 2.0.99e 03-May-2009 - added make_sandbox_from_installed to install from binaries already installed via packages such as .deb, .rpm. - added sample perl test script to MANIFEST. Missed during the previous release - added MySQL::Sandbox::Recipes, a cookbook with short How-To tutorials - cleaned up tests. Added 8 more test to check replication parameters 2.0.99d 02-May-2009 - Added user defined test in Perl, in addition to the ones written in the test_sandbox script language - Updated documentation 2.0.99c 01-May-2009 - Fixed conceptual bug in "start" and "restart". Group sandboxes were not allowing it - added "restart_all" in group sandboxes - Added 18 new tests to check the above problem - Added documentation about port checking and parameters accepted by 'start' and 'restart' 2.0.99b 26-Apr-2009 - added group port checking to make_replication_sandbox and make_multiple_sandbox - added 2 new tests to the test suite to test singkle and group port checking - added documentation on port checking 2.0.99a 12-Apr-2009 - fixed bug in make_replication_sandbox and make_multiple_sandbox. If a group sandbox was the first to be created under $SANDBOX_HOME, it failed. - added check_replication.sb as user defined sample test 2.0.99 11-Apr-2009 - implemented user defined test modules - fixed some documentation glitches - Added documentation about user defined tests 2.0.98i 09-Apr-2009 - added script make_sandbox_from_source, which will create a sandbox from a build directory - Extended maximum port to 64000 - added MySQL versions 5.[2345] as accepted for a Sandbox 2.0.98h 08-Apr-2009 - Changed test_sandbox to use IPC::Open3 instead of qx, when available. This will make the 'make test' output more readable. - added Test_Helper.pm to the test suite 2.0.98g 07-Apr-2009 - added --master_node option to sbtool - added 'preserve' and 'unpreserve' options to sbtool - made test_sandbox TAP compatible - updated the test suite - written the documentation on sbtool to MySQL::Sandbox POD 2.0.98f 06-Apr-2009 - added 'delete' action to sbtool - introduced --export_binaries to make_sandbox - added 03_test_sandbox.t, which uses test_sandbox within the test suite - fixed bug in sbtool. Moving sandbox failed becaus of wrong regular expression - added a test suite for sbtool to test_sandbox test_sandbox --tests=sbtool 2.0.98e 02-Apr-2009 - fixed error in low_level_make_sandbox --interactive. Array values were not preserved correctly wit a default - implemented interactive confirmation for group sandboxes 2.0.98d 01-Apr-2009 - Deprecated "query_analyzer" option :) - moved the POD to MySQL::Sandbox - produced mew README from the POD - implemented --no_check_port (to use as a safeguard with group sandboxes) 2.0.98c 01-Apr-2009 - added query_analyzer option 2.0.98b 31-Mar-2009 - taken most function from sbtool to MySQL::Sandbox module - implemented --check_port for single sandboxes - fixed bug#352222 "report-port incorrect with --master-master" - cleaned up code for parse_options in all scripts - enhanced test case with some tests for the script correctness 2.0.98 29-Mar-2009 - Preparation for version 3.0 - refactoring code to use with ExtUtilis::MakeMaker and install a proper Perl module - updated README - fixed sandbox_action to support 'send_kill' - added $VERSION to both modules 2.0.18 22-Mar-2009 - added change_port script to installed sandboxes - added 'port' operation to sbtool - added --new_port option to sbtool 2.0.17 15-Mar-2009 - improved sbtool error checking - improved sbtool built-in help - added "report-port" to replication slave setup 2.0.16 14-Mar-2009 - added 'copy' option to sbtool, to clone a sandbox data directory into another. 2.0.15 09-Mar-2009 - added "report-host" option to slave creation - fixed server_id for values larger than 10. Instead of folding from 109 to 100, it was doing 109 to 1010. 2.0.15 19-Feb-2009 - added sbtool, a multi purpose program to do administrative tasks with the sandbox. Supported operations: port list, replication tree, moving single and multiple sandboxes 2.0.14 08-Feb-2009 - added code to the "clear" script to truncate the table logs if they exist - improved error messages when using wrong directories or tarballs - added a "change_paths" script to change the sandbox paths quickly when moving the sandbox to a new location. 2.0.13 27-Jan-2009 - added parameters to "start" and "restart" scripts. If you pass an option, it will be passed directly to mysqld_safe. e.g. "start --log=mylog.log" - fixed bug in test_sandbox.pl. Using "ls -d /path/*/" doesn't work on Solaris. Replaced with a more robust routine. - Allow the unpacking of tarballs to work on Solaris if "gtar" is found. 2.0.12 16-Oct-2008 - Fixed small bug in 'clear' script. When the server is not responsive, it was calling the wrong 'kill' script - Applied Greg Haase patch to fix a bug in --datadir_from=dir:xxxx 2.0.11 05-Oct-2008 - Fixed bug#278394, "character '-' in database names" (added backticks to 'clear' script) - added a command to change read attributes inside expanded tarballs to avoid a possible failure in MySQL test suite, should a user run it 2.0.10 27-Aug-2008 - fixed minor bug in make_multiple_sandbox and make_replication_sandbox when passing additional parameters. No space were added at the end. Further parameters were glued together, resulting in a startup error. - added NODE_OPTIONS to work in make_replication_sandbox (it adds options to both MASTER_OPTIONS and SLAVE_OPTIONS) 2.0.9 22-Aug-2008 - fixed bug#260265 "installation fails with log-error option and version < 5" - removed "log-error" from default file - added this option conditionally only if major version > 4 2.0.8 16-Aug-2008 - fixed problem with "~" not being expanded as $HOME - fixed problem with not existent path for tarball - fixed bug#258523 Mysql Sandbox looks for tar.gz in wrong location in make_replication_sandbox, make_sandbox, make_multiple_sandbox, make_multiple_custom_sandbox, and in the test suite - fixed minor problem in MyScripts.pm. log-slow-queries was misspelled, although commented. 2.0.7 06-Aug-2008 - added shortcut option "--circular=N" to make_replication_sandbox corresponding to "--topology=circular --how_many_nodes=N" - added Falcon creation to smoke test (if version >= 6) 2.0.6 20-Jul-2008 - added "check_slaves" script to replication sandboxes 2.0.5 14-Jul-2008 - added named error log to configuration file - add removal of *.err-old files in "clear" script - Fixed bug in circular replication. Unnecessary initialization after stop_all. Added the same check used in standard replication - fixed bug in circular replication. start_all and set_circular_replication.sh were not stopping and starting the slaves in the righ order. - improved 'stop' script. If the server is a slave, calls "stop slave" before closing down. 2.0.4 12-Jul-2008 - fixed bug in test suite. Parameter passing to check routine was often failing on negative tests. Added subroutine prototype to fix the problem. 2.0.3 12-Jul-2008 - Fixed smoke test bugs in test suite. - fixed race condition while checking the pid file - added cleanup of extracted binary with smoke test - added stricter check for InnoDB tables - added some replication tests to test suite 2.0.2 6-Jul-2008 - Fixed minor bugs in low_level_make_sandbox. - When started with --force and --load grants, it said that it failed to comply. In fact, the grants were already loaded. - when started with --force, it invokes $sandbox_dir/start without checking if such script exists 2.0.1 5-Jul-2008 - fixed minor bug on test suite. It fails on Solaris with "ps -ea". Changed to "ps -ef" - added README.wiki - added "smoke" test to test suite - added --no_confirm to all single sandbox testing 2.0.0 2-Jul-2008 - fixed minor bug in generated scripts. Removed bash-specific operator "==" 1.99.10 1-Jul-2008 - Fixed bug in test suite. Process count was not taking into account the pre-test processes. - Fixed bug in test suite. Portability. ps was being used with non portable options. - added --prompt_body option to low_level_make_sandbox - added $SANDBOX_BINARY environment variable, to replace default $HOME/opt/mysql - fixed error message of make_sandbox when invoked without options - added a check in make_sandbox to make sure that we are using GNU tar. 1.99.9 30-Jun-2008 - Fixed bug #244236 (low_level_make_sandbox accepts unnecessary arguments) - Fixed bug in low_level_make_sandbox. sandbox_home was not checked for correctness. It is a simple name, and it should not accept full paths. - INCOMPATIBLE CHANGE home_directory was not supposed to be home. Its name is misleading, and thus it was changed to upper_directory. - Fixed typos in README - Initial fix for bug #239630 (possible failure on non-GNU tar) - fixed script names in "sandbox" script - (Thanks to John Embretsen for most of the reports on today's changes) 1.99.8 29-Jun-2008 - INCOMPATIBLE CHANGE $HOME/sandboxes is now the default SANDBOX_HOME, which users however can override. - INCOMPATIBLE CHANGE "multi_cmd" was renamed "use_all" for name consistency - added a call to low_level_make_sandbox --help when make_sandbox is invoked without the proper syntax. - README has been completely rewritten - added a ./docs directory with the README.pod source for README - added POD to ./sandbox script, to show the documentation when called as "./sandbox manual|help" 1.99.7 28-Jun-2008 - added configurable options for test suite users can now choose which versions and which tests to run from the command line - removed deprecated test_sandbox.sh - moved test suite to ./tests directory - added tests/README - improved "stop" script by combining it with the "kill" script - adjusted make_dist script to use the ./test directory - improved test suite with the ability of running from one or more tarballs instead of the default directories ([$HOME]/opt/mysql) 1.99.6 28-Jun-2008 - enhanced the "clear" script. Now it removes all databases form the data directory, first trying via SQL, then using the OS. - added tests to the test suite to check on this feature 1.99.5 27-Jun-2008 - INCOMPATIBLE CHANGE make_sandbox renamed low_level_make_sandbox easy_sandbox renamed make_sandbox - fixed bug in make_replication_sandbox (base port was not isolated) - added test for circular replication - improved testing for number of processes in the test suite - added circular replication features to make_multiple_sandbox with options --master_master and --circular (this should not be used directly) - added circular replication features to make_replication_sandbox with options --master_master and --topology={standard|circular} . This feature uses make_multiple_sandbox internally. - circular replication uses a separate directory name and port - fixed bug in make_multiple_sandbox. It did not use the $SANDBOX_HOME directory. 1.99.4 21-Jun-2008 - added more extensive test suite in Perl - fixed bug in make_multiple_custom_sandbox (install directory was not set when calling easy_sandbox) 1.99.3 21-Jun-2008 - INCOMPATIBLE CHANGE all Perl script names were changed to make them more intuitive install.pl -> make_sandbox express_install.pl -> easy_sandbox set_replication.pl -> make_replication_sandbox set_many -> make_multiple_sandbox set_custom_many.pl -> make_multiple_custom_sandbox - created a './sandbox' script that lists all applications and eventually executes the one that is passed as argument - mapped "stop" script to faster and safer "kill" script - replaced "sleep 3" with a loop + timeout in shell scripts - removed "sleep" commands from Perl scripts - fixed bug in get_help() : parse_options were not passed to the $msb object 1.99.2 20-Jun-2008 - fixed minor bug. mysql_install_db script in some cases is found in the "bin" directory rather than "scripts" - added ability to log start operations into a log file 1.99.1 19-Jun-2008 - added "kill" script to each sandbox - replace call to "stop" with "kill" in "clear" script 1.99.0 15-Jun-2008 - Started new development branch for Sandbox 2.0 - added MySandbox.pm module, to use the same routines across scripts 1.22 15-Jun-2008 - added support for default options file ($HOME/.msandboxrc) - fixed minor bug in set_replication.pl. Added #master to multi_cmd output. - fixed bug related to location of sample option files. The installer was only looking under "./support-files" while recent packaging use "./share/mysql" - fixed Bug#240121, with a collision between my_file and replication. - added the execution of a "./clear" command when "--force" was used to avoid overwriting a running server. - cleaned up current_changes to contain only not empty options - created a basic test suite (not in distribution yet, only in RCS) 1.21 09-Jun-2008 - added SANDBOX_HOME environmental variable to override $HOME - default sandbox home is now $HOME/sandboxes (if exists) or else it is $HOME, as before - added scripts to start/stop/clear/use all sandboxes at once (if $SANDBOX_HOME != $HOME) 1.20 11-Apr-2008 - Added set_custom_many.pl to install different versions of the server in one go. (Thanks to Ronald Bradford for the idea) - enhanced "multi_cmd" to say which server is running - added support for MYCLIENT_OPTION user variable to pass options to the client (./use and ./multi_cmd) 1.19 06-Apr-2008 - changed installer files so that they can be called from outside the installation directory. 1.18 02-Apr-2008 - Fixed bug in set_many and set_replication. Undefined group directory when setting custom port - Added help to ./express_install 1.17 16-Mar-2008 (not released) - fixed minor bug in "clear: script. It did not remove subdirectories in test db - fixed minor bug on the choice od source dir. If $HOME/opt/mysql exists, it is preferred to /opt/mysql 1.16 04-Jan-2008 (not released) - added stronger check on the result of mysql_install_db. - added removal of general log files and falcon files with the "clear" command. 1.15 09-Dec-2007 - fixed bug in grants.mysql. Removed anonymous users from mysql.db - added $HOME/opt/mysql as possible default for binaries. - added proxy_start script to start a MySQL Proxy instance using the sandboxed server 1.14 24-Oct-2007 - added a set_many.pl command to create several servers not in replication - fixed bug in replication ports assignment. Two replication systems using adjacent versions (e.g. 5.1.22 and 5.1.23) would have clashing port numbers. 1.13 23-Oct-2007 - (INCOMPATIBLE CHANGE) removed '.sh' suffix from all scripts - added version differentiation to replication port and directory. Instead of being always the same, now they are based on the version number, unless modified by the user. - added a multi_cmd script to the replication system, to send a query to each node. - added a 'my' script to call mysql* tools - fixed bug about using 6.0 binaries on Mac OS X (dynamic library path requires a different environment variable) - fixed bug in replication. After a "clear_all", the replication did not start again. Added a "initialize_slaves" script that get called by "start_all" if a clear_all was called. 1.12 17-Oct-2007 - hidden mysql_install_db output on successful execution - fixed argument handling bug in replication scripts 1.11 16-Oct-2007 - all shell scripts are now created from install.pl (not copied) - changed default username, password, and sandbox directory name - forbid using a relative path of tarball 1.10 16-Oct-2007 (not released) - fixed bug on mysql_install_db usage 1.9 15-Oct-2007 (not released) - deprecated the 'archive' method of installation and removed the compressed data directories - express_install can now expand a server tarball. - added support for replicated servers (set_replication.pl) using CHANGE MASTER TO rather than replication options - added 'load_grants' option to install.pl - added 'prompt_prefix' option to install.pl - fixed bug about client library not being available due to LD_LIBRARY_PATH not set 1.8 14-Sep-2007 - Added support for MySQL 6.0 1.7 05-Jul-2006 (not released) - Added support for Mysql 5.2-alpha 1.6 27-May-2006 - Added 'my_clause' command line option to define my.cnf file parameters; - changed interactive routine to allow multi-item options; - changed the shell scripts to be less bash specific. the sandbox should be now more cross-platform than before. During the installation, if bash is not found, then tcsh is used. - new Tutorial available at http://datacharmer.org/#tutorials - bugs fixed: -- clear.sh was using $HOME directory instead of _HOME_DIR_ -- install_version calculated by express_install.pl could be lower than 1024. -- install_version was added twice when loading options from 'current_options.conf' (Thanks to Imran Chaudhry for reporting it) 1.5 24-May-2006 - added 'back' and 'quit' keywords in interactive mode - added express_install.pl, to install quickly from a binary package - Bug fixed. 'start.sh' and 'stop.sh' scripts where using the actual $HOME dorectory instead of the user's defined _HOME_DIR_ 1.4 17-May-2006 (not released) - added support for 3.23, 4.0 and 4.1 installs - default install is now 5.0 - default addition of version to sandbox directory name - added option "no_ver_after_name" to control the above change 1.3 05-May-2006 - added "interactive" option to install through a sort of a wizard - added current_options.conf to record the options used for installing - fix bug in configuration file 1.2 02-May-2006 - minor bug fixes 1.1 19-Apr-2006 - added multiple sources for data directory 1.0 18-Apr-2006 - initial release. MySQL-Sandbox-3.1.04/lib/000755 000765 000024 00000000000 12631550766 015020 5ustar00gmaxstaff000000 000000 MySQL-Sandbox-3.1.04/LICENSE000644 000765 000024 00000026136 12566053633 015265 0ustar00gmaxstaff000000 000000 Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "{}" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright {yyyy} {name of copyright owner} Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. MySQL-Sandbox-3.1.04/Makefile.PL000644 000765 000024 00000002310 12566333524 016216 0ustar00gmaxstaff000000 000000 use strict; use warnings; use ExtUtils::MakeMaker; WriteMakefile( NAME => 'MySQL::Sandbox', VERSION_FROM => 'lib/MySQL/Sandbox.pm', # finds $VERSION PREREQ_PM => { 'File::Find' => 1.0, 'Socket' => 1.7, }, EXE_FILES => [ 'bin/msb', 'bin/msandbox', 'bin/sbtool', 'bin/test_sandbox', 'bin/low_level_make_sandbox', 'bin/make_sandbox', 'bin/make_sandbox_from_source', 'bin/make_sandbox_from_installed', 'bin/make_replication_sandbox', 'bin/make_multiple_sandbox', 'bin/make_multiple_custom_sandbox', 'bin/deploy_to_remote_sandboxes.sh', ], LICENSE => 'apache', ($] >= 5.005 ? ( ABSTRACT_FROM => 'lib/MySQL/Sandbox.pm', AUTHOR => 'Giuseppe Maxia ' ) : ()), ); MySQL-Sandbox-3.1.04/MANIFEST000644 000765 000024 00000003041 12631550766 015401 0ustar00gmaxstaff000000 000000 LICENSE Changelog MANIFEST Makefile.PL README.md bin/deploy_to_remote_sandboxes.sh bin/low_level_make_sandbox bin/make_multiple_custom_sandbox bin/make_multiple_sandbox bin/make_replication_sandbox bin/make_sandbox bin/make_sandbox_from_installed bin/make_sandbox_from_source bin/msandbox bin/msb bin/sbtool bin/test_sandbox lib/MySQL/Sandbox.pm lib/MySQL/Sandbox/Recipes.pm lib/MySQL/Sandbox/Scripts.pm t/01_modules.t t/02_test_binaries.t t/03_test_sandbox.t t/04_test_sbtool.t t/05_test_smoke.t t/06_test_user_defined.t t/07_test_user_defined.t t/08_test_single_port_checking.t t/09_test_multiple_port_checking.t t/10_check_start_restart.t t/11_replication_parameters.t t/12_custom_user_pwd.t t/13_innodb_plugin_install.t t/14_semi_synch_plugin_install.t t/15_user_privileges.t t/16_replication_options.t t/17_replication_flow.t t/18_force_creation.t t/19_replication_gtid.t t/20_add_option.t t/Test_Helper.pm t/add_option.sb.pl t/check_replication.sb t/check_single_server.sb t/custom_user_pwd.sb.pl t/force.sb.pl t/group_port_checking.sb t/group_port_checking.sb.pl t/innodb_plugin_install.sb.pl t/replication_flow.sh t/replication_gtid.sb.pl t/replication_options.sb.pl t/replication_parameters.sb.pl t/semi_synch_plugin_install.sb.pl t/single_port_checking.sb t/single_port_checking.sb.pl t/start_restart_arguments.sb t/start_restart_arguments.sb.pl t/user_privileges.sb t/user_privileges.sb.pl META.yml Module YAML meta-data (added by MakeMaker) META.json Module JSON meta-data (added by MakeMaker) MySQL-Sandbox-3.1.04/META.json000644 000765 000024 00000001717 12631550766 015701 0ustar00gmaxstaff000000 000000 { "abstract" : "Quickly installs one or more MySQL servers in the same host, either standalone or in groups", "author" : [ "Giuseppe Maxia " ], "dynamic_config" : 1, "generated_by" : "ExtUtils::MakeMaker version 6.66, CPAN::Meta::Converter version 2.133380", "license" : [ "apache_2_0" ], "meta-spec" : { "url" : "http://search.cpan.org/perldoc?CPAN::Meta::Spec", "version" : "2" }, "name" : "MySQL-Sandbox", "no_index" : { "directory" : [ "t", "inc" ] }, "prereqs" : { "build" : { "requires" : { "ExtUtils::MakeMaker" : "0" } }, "configure" : { "requires" : { "ExtUtils::MakeMaker" : "0" } }, "runtime" : { "requires" : { "File::Find" : "1", "Socket" : "1.7" } } }, "release_status" : "stable", "version" : "v3.1.04" } MySQL-Sandbox-3.1.04/META.yml000644 000765 000024 00000001071 12631550766 015522 0ustar00gmaxstaff000000 000000 --- abstract: 'Quickly installs one or more MySQL servers in the same host, either standalone or in groups' author: - 'Giuseppe Maxia ' build_requires: ExtUtils::MakeMaker: 0 configure_requires: ExtUtils::MakeMaker: 0 dynamic_config: 1 generated_by: 'ExtUtils::MakeMaker version 6.66, CPAN::Meta::Converter version 2.133380' license: apache meta-spec: url: http://module-build.sourceforge.net/META-spec-v1.4.html version: 1.4 name: MySQL-Sandbox no_index: directory: - t - inc requires: File::Find: 1 Socket: 1.7 version: v3.1.04 MySQL-Sandbox-3.1.04/README.md000644 000765 000024 00000075324 12631363502 015532 0ustar00gmaxstaff000000 000000 # NAME MySQL::Sandbox - Quickly installs one or more MySQL servers in the same host, either standalone or in groups # SYNOPSIS make_sandbox /path/to/MySQL-VERSION.tar.gz export SANDBOX_BINARY=$HOME/opt/mysql make_sandbox --export_binaries /path/to/MySQL-VERSION.tar.gz make_sandbox $SANDBOX_BINARY/VERSION make_sandbox VERSION # PURPOSE This package is a sandbox for testing features under any version of MySQL from 3.23 to 5.x (and MariaDB 10). It will install one node under your home directory, and it will provide some useful commands to start, use and stop this sandbox. With this package you can play with new MySQL releases without need of using other computers. The server installed in the sandbox use non-standard data directory, ports and sockets, so they won't interfere with existing MYSQL installations. # INSTALLATION MySQL Sandbox installs as a normal Perl Module. Since its purpose is to install side servers in user space, you can install it as root (default) or as an unprivileged user. In this case, you need to set the PERL5LIB and PATH variables. # as root perl Makefile.PL make make test make install # as normal user export PATH=$HOME/usr/local/bin:$PATH export PERL5LIB=$HOME/usr/local/lib/perl5/site_perl/x.x.x perl Makefile.PL PREFIX=$HOME/usr/local make make test make install Notice that PERL5LIB could be different in various operating systems. If you opt for this installation method, you must adapt it to your operating system path and Perl version. See also under ["TESTING"](#testing) for more options before running 'make test' # MAKING SANDBOXES ## Single server sandbox The easiest way to make a sandbox is 1. download the sandbox package and install it as instructed above 2. download a MySQL binary tarball 3. run this command $ make_sandbox /path/to/mysql-X.X.XX-osinfo.tar.gz That's all it takes to get started. The Sandbox will ask you for confirmation, and then it will tell you where it has installed your server. By default, the sandbox creates a new instance for you under $SANDBOX_HOME/msb_X_X_XX ## Making a replication sandbox It's as easy as making a single sandbox $ make_replication_sandbox /path/to/mysql-X.X.XX-osinfo.tar.gz This will create a new instance of one master and two slaves under $SANDBOX_HOME/rsandbox_X_X_XX ## Circular replication It requires an appropriate option when you start a replication sandbox $ make_replication_sandbox --circular=4 /path/to/mysql-X.X.XX-osinfo.tar.gz This will create a replication system with three servers connected by circular replication. A handy shortcut is `--master_master`, which will create a circular replication system of exactly two members. ## Multiple sandboxes You can create a group of sandboxes without any replication among its members. If you need three servers of the same version, you can use $ make_multiple_sandbox /path/to/tarball If you need servers of different versions in the same group, you may like $ make_multiple_custom_sandbox /path/to/tarball1 path/to/tarball2 /path/to/tb3 Assuming that each tarball is from a different version, you will group three servers under one directory, with the handy sandbox scripts to manipulate them. ## Creating a sandbox from source If you want to create a sandbox from the code that you have just compiled, but you don't want to install, there is a script that makesa binary tarball for you and installs a sandbox in one go. $ make_sandbox_from_source {SOURCE_DIRECTORY} {sandbox_type} [options] The first parameters is the directory where you have successfully run "./configure && make". The second parameter is what kind of sandbox you want to create: One of the following: * single * multiple * replication * circular You can then add all the options you need at the end. For example: $ make_sandbox_from_source $HOME/build/5.0 single --export_binaries --check_port or $ make_sandbox_from_source $HOME/build/5.0 replication --how_many_slaves=5 If you call this program several times from the same directory, it will check if the compiled binaries are newer than the extracted ones, and if they aren't, it will reuse the ones created during the previous run, thus saving time and CPU. ## Creating a sandbox from already installed binaries The script `make_sandbox_from_installed` tries to create a sandbox using already installed binaries. Since these binaries can be in several different places, the script creates a container with symbolic links, where the binaries (their links, actually) are arranged as MySQL Sandbox expects them to be. To use this version, change directory to a place where you want to store this symbolic links container, and invoke make_sandbox_from_installed X.X.XX [options] where X.X.XX is the version number. You can then pass any options accepted by make\_sandbox. ## Defaults and shortcuts If you use sandboxes often, instead of pointing to a tarball you can set a directory containing expanded tarballs. By default, the sandbox looks under $HOME/opt/mysql and /opt/mysql The expanded tarballs must be named with the full version. e.g. $HOME/opt/mysql/5.0.64 /opt/mysql/5.1.24 If you have such an organization, then you can invoke every sandbox script with this abridged syntax: make_sandbox 5.0.64 make_replication_sandbox 5.1.25 make_multiple_custom_sandbox 5.0.64 5.1.25 If you use some options frequently, it would make sense to add them to the default option file, which is $HOME/.msandboxrc ## Fine tuning Every sandbox script will give you additional information if you invoke it with the "--help" option. When creating a single sandbox, you can pass to the new server most any option that can be used in a my.cnf file, in addition to specific sandbox options. Multiple and replication sandboxes, for example, accept a --how\_many\_slaves=X or --how\_many\_nodes=X option, allowing you to create very large groups. ## SANDBOX HOME Unless you override the defaults, sandboxes are created inside a directory that servers two purposes: - further isolates the sandboxes, and keep them under easy control if you are in the habit of creating many of them; - provides a set of handy super-commands, which can be passed to all the sandboxes. Running "$SANDBOX\_HOME/stop\_all" you will stop all servers of all sandboxes, single or groups, below that directory. # USING A SANDBOX Change directory to the newly created one (default: $SANDBOX\_HOME/msb\_VERSION for single sandboxes) The sandbox directory of the instance you just created contains some handy scripts to manage your server easily and in isolation. - start - restart - stop "./start", "./restart", and "./stop" do what their name suggests. `start` and `restart` accept parameters that are eventually passed to the server. e.g.: ./start --skip-innodb ./restart --event-scheduler=disabled - use "./use" calls the command line client with the appropriate parameters, - clear "./clear" stops the server and removes everything from the data directory, letting you ready to start from scratch. - multiple server sandbox On a replication sandbox, you have the same commands, with a "\_all" suffix, meaning that you propagate the command to all the members. Then you have "./m" as a shortcut to use the master, "./s1" and "./s2" to access the slaves (and "s3", "s4" ... if you define more). In group sandboxes without a master slave relationship (circular replication and multiple sandboxes) the nodes can be accessed by ./n1, ./n2, ./n3, and so on. - start\_all - restart\_all - stop\_all - use\_all - clear\_all - m - s1,s2 ## Database users There are 2 database users installed by default: +-----------------+-------------+-------------------------------+ | user name | password | privileges | +-----------------+-------------+-------------------------------+ | root@localhost | msandbox | all on *.* with grant option | | msandbox@% | msandbox | all on *.* | | rsandbox@127.% | rsandbox | REPLICATION SLAVE | | | | (only replication sandboxes) | +-----------------+-------------+-------------------------------+ ## Ports and sockets Ports are created from the server version. a 5.1.25 server will use port 5125, unless you override the default. Replicated and group sandboxes add a delta number to the version figure, to avoid clashing with single installations. (note: ports can be overridden using -P option during install) +--------+-----------------------------+ | port | socket | +--------+-----------------------------+ | 3310 | /tmp/mysql_sandbox3310.sock | +--------+-----------------------------+ ## Searching for free ports MySQL Sandbox uses a fairly reasonable system of default ports that guarantees the usage of unused ports most of the times. If you are creating many sandbozes, however, especially if you want several sandboxes using the same versions, collisions may happen. In these cases, you may ask for a port check before installing, thus making sure that your sandbox is really not conflicting with anything. ### Single sandbox port checking The default behavior when asking to install a sandbox over an existing one is to abort. If you specify the `--force` option, the old sandbox will be saved as 'old\_data' and a new one created. Instead, using the `--check_port` option, MySQL Sandbox searches for the first available unused port, and uses it. It will also create a non conflicting data directory. For example make_sandbox 5.0.79 # creates a sandbox with port 5079 under $SANDBOX_HOME/msb_5_0_79 A further call to the same command will be aborted unless you specify either `--force` or `--check_port`. make_sandbox 5.0.79 -- --force # Creates a sandbox with port 5079 under $SANDBOX_HOME/msb_5_0_79 # The contents of the previous data directory are saved as 'old_data'. make_sandbox 5.0.79 -- --check_port # Creates a sandbox with port 5080 under $SANDBOX_HOME/msb_5_0_79_a make_sandbox 5.0.79 -- --check_port # Creates a sandbox with port 5081 under $SANDBOX_HOME/msb_5_0_79_b Notice that this option is disabled when you use a group sandbox (replication or multiple). Even if you set NODE\_OPTIONS=--check\_port, it won't be used, because every group sandbox invokes make\_sandbox with the --no\_check\_port option. ### Multiple sandbox port checking When you create a multiple sandbox (make\_replication\_sandbox, make\_multiple\_sandbox, make\_multiple\_custom\_sandbox) the default behavior is to overwrite the existing sandbox without asking for confirmation. The rationale is that a multiple sandbox is definitely more likely to be a created only for testing purposes, and overwriting it should not be a problem. If you want to avoid overwriting, you can specify a different group name (`--replication_directory` `--group_directory`), but this will use the same base port number, unless you specify `--check_base_port`. make_replication_sandbox 5.0.79 # Creates a replication directory under $SANDBOX_HOME/rsandbox_5_0_79 # The default base_port is 7000 make_replication_sandbox 5.0.79 # Creates a replication directory under $SANDBOX_HOME/rsandbox_5_0_79 # overwriting the previous one. The default base port is still 7000 # WRONG make_replication_sandbox --check_base_port 5.0.79 # Creates a replication directory under $SANDBOX_HOME/rsandbox_5_0_79 # overwriting the previous one. # WRONG make_replication_sandbox --replication_directory=newdir 5.0.79 # Created a replication directory under $SANDBOX_HOME/newdir. # The previous one is preserved, but the new sandbox does not start # because of port conflict. # RIGHT make_replication_sandbox --replication_directory=newwdir \ --check_base_port 5.0.79 # Creates a replication directory under $SANDBOX_HOME/newdir # The previous one is preserved. No conflicts happen ## Environment variables All programs in the Sandbox suite recognize and use the following variables: * HOME the user's home directory; ($HOME) * SANDBOX_HOME the place where the sandboxes are going to be built. ($HOME/sandboxes by default) * USER the operating system user; * PATH the execution path; * if SBDEBUG if set, the programs will print debugging messages In addition to the above, make\_sandbox will use \* SANDBOX\_BINARY or BINARY\_BASE the directory containing the installation server binaries (default: $HOME/opt/mysql) make\_replication\_sandbox will recognize the following \* MASTER\_OPTIONS additional options to be passed to the master \* SLAVE\_OPTIONS additional options to be passed to each slave \* NODE\_OPTIONS additional options to be passed to each node The latter is also recognized by make\_multiple\_custom\_sandbox and make\_multiple\_sandbox The test suite, `test_sandbox`, recognizes two environment variables * TEST_SANDBOX_HOME, which sets the path where the sandboxes are installed, if the default $HOME/test_sb is not suitable. It is used when you test the package with 'make test' * PRESERVE_TESTS. If set, this variable prevents the removal of test sandboxes created by test_sandbox. It is useful to inspect sandboxes if a test fails. ## msb - the Sandbox shortcut When you have many sandboxes, even the simple exercise of typing the path to the appropriate 'use' script can be tedious and seemingly slow. If saving a few keystrokes is important, you may consider using `msb`, the sandbox shortcut. You invoke 'msb' with a version number, without dots or underscores. The shortcut script will try its best at finding the right directory. $ msb 5135 # same as calling # $SANDBOX_HOME/msb_5_1_35/use Every option that you use after the version is passed to the 'use' script. $ msb 5135 -e "SELECT VERSION()" # same as calling # $SANDBOX_HOME/msb_5_1_35/use -e "SELECT VERSION()" Prepending a "r" to the version number indicates a replication sandbox. If the directory is found, the script will call the master. $ msb r5135 # same as calling # $SANDBOX_HOME/rsandbox_5_1_35/m To use a slave, use the corresponding number immediately after the version. $ msb r5135 2 # same as calling # $SANDBOX_HOME/rsandbox_5_1_35/s2 Options for the destination script are added after the node indication. $ msb r5135 2 -e "SELECT 1" # same as calling # $SANDBOX_HOME/rsandbox_5_1_35/s2 -e "SELECT 1" Similar to replication, you can call multiple sandboxes, using an 'm' before the version number. $ msb m5135 # same as calling # $SANDBOX_HOME/multi_msb_5_1_35/n1 $ msb m5135 2 # same as calling # $SANDBOX_HOME/multi_msb_5_1_35/n2 If your sandbox has a non-standard name and you pass such name instead of a version, the script will attempt to open a single sandbox with that name. $ msb testSB # same as calling # $SANDBOX_HOME/testSB/use If the identified sandbox is not active, the script will attempt to start it. This shortcut script doesn't deal with any sandbox script other than the ones listed in the above examples. But the msb can do even more. If you invoke it with a dotted version number, the script will run the appropriate make\*sandbox script and then use the sandbox itself. $ msb 5.1.35 # same as calling # make_sandbox 5.1.35 -- --no_confirm # and then # $SANDBOX_HOME/msb_5_1_35/use It works for group sandboxes as well. $ msb r5.1.35 # same as calling # make_replication_sandbox 5.1.35 # and then # $SANDBOX_HOME/rsandbox_5_1_35/m And finally, it also does What You Expect when using a tarball instead of a version. $ msb mysql-5.1.35-YOUR_OS.tar.gz # creates and uses a single sandbox from this tarball $ msb r mysql-5.1.35-YOUR_OS.tar.gz # creates and uses a replication sandbox from this tarball $ msb m mysql-5.1.35-YOUR_OS.tar.gz # creates and uses a multiple sandbox from this tarball Using a MySQL server has never been easier. # SBTool the Sandbox helper The Sandbox Helper, `sbtool`, is a tool that allows administrative operations on already existing sandboxes. It does a number of important tasks that are not available at creation time or that would require too much manual labor. usage: sbtool [options] -o --operation (s) <> - what task to perform 'info' returns configuration options from a Sandbox 'copy' copies data from one Sandbox to another 'ports' lists ports used by the Sandbox 'tree' creates a replication tree 'move' moves a Sandbox to a different location 'range' finds N consecutive ports not yet used by the Sandbox 'port' Changes a Sandbox port 'delete' removes a sandbox completely 'preserve' makes a sandbox permanent 'unpreserve' makes a sandbox NOT permanent 'plugin' installs a given plugin -s --source_dir (s) <> - source directory for move,copy -d --dest_dir (s) <> - destination directory for move,copy -n --new_port (s) <> - new port while moving a sandbox -u --only_used (-) <> - for "ports" operation, shows only the used ones -i --min_range (i) <5000> - minimum port when searching for available ranges -x --max_range (i) <64000> - maximum port when searching for available ranges -z --range_size (i) <10> - size of range when searching for available port range -f --format (s) - format for "ports" and "info" 'perl' fully structured information in Perl code 'text' plain text dump of requested information -p --search_path (s) - search path for ports and info -a --all_info (-) <> - print more info for "ports" operation --tree_nodes (s) <> - description of the tree (x-x x x-x x|x x x|x x) --mid_nodes (s) <> - description of the middle nodes (x x x) --leaf_nodes (s) <> - description of the leaf nodes (x x|x x x|x x) --tree_dir (s) <> - which directory contains the tree nodes --plugin (s) <> - which plugin needs to be installed --plugin_file (s) <> - which plugin template file should be used -v --verbose (-) <> - prints more info on some operations -h --help (-) <1> - this screen ## sbtool - Informational options ### sbtool -o info Returns configuration options from a Sandbox (if specified) or from all sandboxes under $SANDBOX\_HOME (default). You can use `--search_path` to tell sbtool where to start. The return information is formatted as a Perl structure. ### sbtool -o ports Lists ports used by the Sandbox. Use `--search_path` to tell sbtool where to start looking (default is $SANDBOX\_HOME). You can also use the `--format` option to influence the outcome. Currently supported are only 'text' and 'perl'. If you add the `--only_used` option, sbtool will return only the ports that are currently open. ### sbtool -o range Finds N consecutive ports not yet used by the Sandbox. It uses the same options used with 'ports' and 'info'. Additionally, you can define the low and high boundaries by means of `--min_range` and `--max_range`. The size of range to search is 10 ports by default. It can be changed with `--range_size`. ## sbtool - modification options ### sbtool -o port Changes port to an existing Sandbox. This requires the options `--source_dir` and `--new_port` to complete the task. If the sandbox is running, it will be stopped. ### sbtool -o copy Copies data from one Sandbox to another. It only works on **single** sandboxes. It requires the `--source_dir` and `--dest_dir` options to complete the task. Both Source and destination directory must be already installed sandboxes. If any of them is still running, it will be stopped. If both source and destination directory point to the same directory, the command is not performed. At the end of the operation, all the data in the source sandbox is copied to the destination sandbox. Existing files will be overwritten. It is advisable, but not required, to run a "./clear" command on the destination directory before performing this task. ### sbtool -o move Moves a Sandbox to a different location. Unlike 'copy', this operation acts on the whole sandbox, and can move both single and multiple sandboxes. It requires the `--source_dir` and `--dest_dir` options to complete the task. If the destination directory already exists, the task is not performed. If the source sandbox is running, it will be stopped before performing the operation. After the move, all paths used in the sandbox scripts will be changed. ### sbtool -o tree Creates a replication tree, with one master, one or more intermediate level slaves, and one or more leaf node slaves for each intermediate level. To create the tree, you need to create a multiple nodes sandbox (using `make_multiple_sandbox`) and then use `sbtool` with the following options: * --tree_dir , containing the sandbox to convert to a tree * --master_node, containing the node that will be master * --mid_nodes, with a list of nodes for the intermediate level * --leaf_nodes, with as many lists as how many mid_nodes Each list is separated from the next by a pipe sign (|). Alternatively, you can use the `--tree_nodes` option to describe all the tree at once. For example, in a sandbox with 8 nodes, to define 1 as master node, nodes 2 and 3 as middle nodes, nodes 4, 5, and 6 as slaves of node 2 and nodes 7 and 8 as slaves of node 3, you can use either of the following: sbtool --tree_dir=/path/to/source \ --master_node=1 \ --mid_nodes='2 3' --leaf_nodes='4 5 6|7 8' sbtool --tree_dir=/path/to/source \ --tree_nodes='1 - 2 3 - 4 5 6|7 8' ### sbtool -o preserve Makes a sandbox permanent. It requires the `--source_dir` option to complete the task. This command changes the 'clear' command within the requested sandbox, disabling its effects. The sandbox can't be erased using 'clear' or 'clear\_all'. The 'delete' operation of sbtool will skip a sandbox that has been made permanent. ### sbtool -o unpreserve Makes a sandbox NOT permanent. It requires the `--source_dir` option to complete the task. This command cancels the changes made by a 'preserve' operation, making a sandbox erasable with the 'clear' command. The 'delete' operation can be performed successfully on an unpreserved sandbox. ### sbtool -o delete Removes a sandbox completely. It requires the `--source_dir` option to complete the task. The requested sandbox will be stopped and then deleted completely. WARNING! No confirmation is asked! ### sbtool -o plugin Installs a given plugin into a sandbox. It requires the `--source_dir` and `--plugin` options to complete the task. The plugin indicated must be defined in the plugin template file, which is by default installed in `$SANDBOX_HOME`. Optionally, you can indicate a different plugin template with the `--plugin_file` option. By default, sbtool looks for the plugin template file in the sandbox directory that is the target of the installation. If it is not found there, it will look at `$SANDBOX_HOME` before giving up with an error. #### Plugin template The Plugin template is a Perl script containing the definition of the templates you want to install. Each plugin must have at least one target **Server type**, which could be one of _all\_servers_, _master_, or _slave_. It is allowed to have more than one target types in the same plugin. Each server type, in turn, must have at least one section named **operation\_sequence**, an array reference containing the list of the actions to perform. Such actions can be regular scripts in each sandbox (start, stop, restart, clear) or one of the following template sections: - options\_file It is the list of lines to add to an options file, under the `[mysqld]` label. - sql\_commands It is a list of queries to execute. Every query must have appropriate semicolons as required. If no semicolon are found in the list, no queries are executed. - startup\_file It is a file, named _startup.sql_, to be created under the data directory. It will contain the lines indicated in this section. You must remember to add a line 'init-file=startup.sql' to the options\_file section. # TESTING ## test\_sandbox The MySQL Sandbox comes with a test suite, called test\_sandbox, which by default tests single,replicated, multiple, and custom installations of MySQL version 5.0.77 and 5.1.32.You can override the version being tested by means of command line options: test_sandbox --versions=5.0.67,5.1.30 or you can specify a tarball test_sandbox --versions=/path/to/mysql-tarball-5.1.31.tar.gz test_sandbox --tarball=/path/to/mysql-tarball-5.1.31.tar.gz You can also define which tests you want to run: test_sandbox --tests=single,replication ## Test isolation The tests are not performed in the common `$SANDBOX_HOME` directory, but on a separate directory, which by default is `$HOME/test_sb`. To avoid interferences, before the tests start, the application runs the `$SANDBOX_HOME/stop_all` command. The test directory is considered to exist purely for testing purposes, and it is erased several times while running the suite. Using this directory to store valuable data is higly risky. ## Tests during installation When you build the package and run make test test\_sandbox is called, in addition to many other tests in the ./t directory, and the tests are performed on a temporary directory under `$INSTALLATION_DIRECTORY/t/test_sb`. By default, version 5.6.26 is used. If this version is not found in `$HOME/opt/mysql/`, the test is skipped. You can override this option by setting the TEST\_VERSION environment variable. TEST_VERSION=5.7.9 make test TEST_VERSION=$HOME/opt/mysql/5.7.9 make test TEST_VERSION=/path/to/myswl-tarball-5.7.9.tar.gz make test ## User defined tests Starting with version 2.0.99, you can define your own tests, and run them by $ test_sandbox --user_test=file_name ### simplified test script Inside your test file, you can define test actions. There are two kind of tests: shell and sql the test type is defined by a keyword followed by a colon. The 'shell' test requires a 'command', which is passed to a shell. The 'expected' label is a string that you expect to find within the shell output. If you don't expect anything, you can just say "expected = OK", meaning that you will be satisfied with a ZERO exit code reported by the operating system. The 'msg' is the description of the test that is shown to you when the test runs. shell: command = make_sandbox 5.1.30 -- --no_confirm expected = sandbox server started msg = sandbox creation The 'sql' test requires a 'path', which is the place where the test engine expects to find a 'use' script. The 'query' is passed to the above mentioned script and the output is captured for further processing. The 'expected' parameter is a string that you want to find in the query output. The 'msg' parameter is like the one used with the 'shell' test. sql: path = $SANDBOX_HOME/msb_5_1_30 query = select version() expected = 5.1.30 msg = checking version All strings starting with a $ are expanded to their corresponding environment variables. For example, if $SANDBOX\_HOME is /home/sb/tests, the line command = $SANDBOX_HOME/msb_5_1_30/stop will expand to: command = /home/sb/tests/msb_5_1_30/stop ### Perl based test scripts In addition to the internal script language, you can also define perl scripts, which will be able to use the $sandbox\_home global variable and to call routines defined inside test\_sandbox. (see list below) To be identified as a Perl script, the user defined test must have the extension ".sb.pl" - ok\_shell() The `ok_shell` function requires a hash reference containing the following labels: A 'command', which is passed to a shell. The 'expected' label is a string that you expect to find within the shell output. If you don't expect anything, you can just say "expected = OK", meaning that you will be satisfied with a ZERO exit code reported by the operating system. The 'msg' is the description of the test that is shown to you when the test runs. ok_shell($hashref) ok_shell({ command => 'make_sandbox 5.1.30 --no_confirm', expected => 'sandbox server started', msg => 'sandbox creation', }) - ok\_sql() The `ok_sql` function requires a hashref containing the following labels: A 'path', which is the place where the test engine expects to find a 'use' script. The 'query' is passed to the above mentioned script and the output is captured for further processing. The 'expected' parameter is a string that you want to find in the query output. The 'msg' parameter is like the one used with the ok\_exec function. - get\_bare\_version() This function accepts one parameter, which can be either a MySQL tarball name or a version, and returns the bare version found in the input string. If called in list mode, it returns also a normalized version string with dots replaced by underscores. my $version = get_bare_version('5.1.30'); # returns '5.1.30' my $version = get_bare_version('mysql-5.1.30-OS.tar.gz'); # returns '5.1.30' my ($version,$dir_name) = get_bare_version('mysql-5.1.30-OS.tar.gz'); # returns ('5.1.30', '5_1_30') - ok This is a low level function, similar to the one provided by Test::More. You should not need to call this one directly, unless you want to fine tuning a test. See the test script t/start\_restart\_arguments.sb.pl as an example # REQUIREMENTS To use this package you need at least the following: - Linux or Mac OSX operating system (it may work in other \*NIX OSs, but has not been tested) - A binary tarball of MySQL 3.23 or later - Perl 5.8.1 or later - Bash shell # COPYRIGHT Version 3.1 Copyright (C) 2006-2015 Giuseppe Maxia Home Page http://github.com/datacharmer # LEGAL NOTICE Copyright 2006-2015 Giuseppe Maxia Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. MySQL-Sandbox-3.1.04/t/000755 000765 000024 00000000000 12631550766 014515 5ustar00gmaxstaff000000 000000 MySQL-Sandbox-3.1.04/t/01_modules.t000644 000765 000024 00000000764 12566053633 016657 0ustar00gmaxstaff000000 000000 use strict; use warnings; use Test::More ; BEGIN { if ($^O =~ /^(?:mswin|win)/i) { diag 'NOT SUPPORTED ON WINDOWS'; plan skip_all => 'This module is not for Windows'; } else { plan tests => 3; use_ok('MySQL::Sandbox') ; use_ok('MySQL::Sandbox::Scripts') ; use_ok('MySQL::Sandbox::Recipes') ; } } #BEGIN { use_ok('MySQL::Sandbox') }; #BEGIN { use_ok('MySQL::Sandbox::Scripts') }; #BEGIN { use_ok('MySQL::Sandbox::Recipes') }; MySQL-Sandbox-3.1.04/t/02_test_binaries.t000644 000765 000024 00000005173 12566053633 020042 0ustar00gmaxstaff000000 000000 BEGIN { $ENV{PERL5LIB}="$ENV{PWD}/lib"; $ENV{PATH}="$ENV{PWD}/bin:$ENV{PATH}"; }; use strict; use warnings; use lib './t'; use Test_Helper; use Test::More; BEGIN { if ($^O =~ /^(?:mswin|win)/i) { plan skip_all => 'This module is not for Windows' } else { plan tests => 36; } } # 7 tests ok_shell_result( "msandbox", ['available', 'low_level_make_sandbox', 'make_sandbox', 'make_replication_sandbox', 'make_multiple_sandbox', 'make_multiple_custom_sandbox'], "msandbox"); # 5 tests ok_shell_result( "msb", ['shortcut', 'single', 'replication', 'multiple' ], "msb" ); # 3 tests ok_shell_result( "low_level_make_sandbox --help", ['low_level_make_sandbox', '-d --sandbox_directory = name'], "low_level_make_sandbox"); # 3 tests # my @time_items = localtime(time); # my $year = $time_items[5] + 1900; ok_shell_result( "make_sandbox --help", ['make_sandbox', 'version', # "2006-$year" ], "make_sandbox"); # 3 tests ok_shell_result( "make_replication_sandbox --help", ['make_replication_sandbox', '--sandbox_base_port = number'], "make_replication_sandbox"); # 3 tests ok_shell_result( "make_multiple_sandbox --help", ['make_multiple_sandbox', '--sandbox_base_port = number'], "make_multiple_sandbox"); # 3 tests ok_shell_result( "make_multiple_custom_sandbox --help", ['make_multiple_custom_sandbox', '--sandbox_base_port = number'], "make_multiple_custom_sandbox"); # 3 tests ok_shell_result( "sbtool --help", ['sbtool', '--operation'], "sbtool"); # 3 tests ok_shell_result( "test_sandbox --help", ['test_sandbox', '--tarball=/path/to/tarball'], "test_sandbox"); # 3 tests ok_shell_result( "make_sandbox_from_source", ['make_sandbox_from_source', 'configure && make'], "make_sandbox_from_source"); sub ok_shell { my ($command , $description) = @_; my $result = system($command); # warn "\n<$?><$result>\n"; return ok($? >=0 , $description); } sub ok_shell_result { my ($command, $search_items, $description) = @_; $? = 0; $! = undef; my $result = qx($command); # diag ">>$result\n"; ok($? >= 0 , $description); for my $item (@{ $search_items}) { ok( $result =~ /$item/ , "$description - $item" ); } } MySQL-Sandbox-3.1.04/t/03_test_sandbox.t000644 000765 000024 00000000252 12566053633 017676 0ustar00gmaxstaff000000 000000 use lib './t'; use Test_Helper; # test_sandbox( "test_sandbox --versions=$ENV{TEST_VERSION}", 125); test_sandbox( "test_sandbox --versions=$ENV{TEST_VERSION}", 194, 1); MySQL-Sandbox-3.1.04/t/04_test_sbtool.t000644 000765 000024 00000000160 12566053633 017541 0ustar00gmaxstaff000000 000000 use lib './t'; use Test_Helper; test_sandbox( 'test_sandbox --tests=sbtool --versions=$ENV{TEST_VERSION}', 34); MySQL-Sandbox-3.1.04/t/05_test_smoke.t000644 000765 000024 00000000121 12566053633 017353 0ustar00gmaxstaff000000 000000 use lib './t'; use Test_Helper; test_sandbox( 'test_sandbox --tests=smoke', 19); MySQL-Sandbox-3.1.04/t/06_test_user_defined.t000644 000765 000024 00000000154 12566053633 020700 0ustar00gmaxstaff000000 000000 use lib './t'; use Test_Helper; test_sandbox( 'test_sandbox --user_test=./t/check_single_server.sb', 3, 0); MySQL-Sandbox-3.1.04/t/07_test_user_defined.t000644 000765 000024 00000000164 12566053633 020702 0ustar00gmaxstaff000000 000000 use lib './t'; use Test_Helper; test_sandbox( 'test_sandbox --tests=user --user_test=./t/check_replication.sb', 4); MySQL-Sandbox-3.1.04/t/08_test_single_port_checking.t000644 000765 000024 00000000172 12566053633 022426 0ustar00gmaxstaff000000 000000 use lib './t'; use Test_Helper; test_sandbox( 'test_sandbox --tests=user --user_test=./t/single_port_checking.sb.pl', 6); MySQL-Sandbox-3.1.04/t/09_test_multiple_port_checking.t000644 000765 000024 00000000172 12566053633 023001 0ustar00gmaxstaff000000 000000 use lib './t'; use Test_Helper; test_sandbox( 'test_sandbox --tests=user --user_test=./t/group_port_checking.sb.pl', 16); MySQL-Sandbox-3.1.04/t/10_check_start_restart.t000644 000765 000024 00000000161 12566053633 021234 0ustar00gmaxstaff000000 000000 use lib './t'; use Test_Helper; test_sandbox( 'test_sandbox --user_test=./t/start_restart_arguments.sb.pl', 35); MySQL-Sandbox-3.1.04/t/11_replication_parameters.t000644 000765 000024 00000000157 12566053633 021740 0ustar00gmaxstaff000000 000000 use lib './t'; use Test_Helper; test_sandbox( 'test_sandbox --user_test=./t/replication_parameters.sb.pl', 9); MySQL-Sandbox-3.1.04/t/12_custom_user_pwd.t000644 000765 000024 00000000150 12566053633 020420 0ustar00gmaxstaff000000 000000 use lib './t'; use Test_Helper; test_sandbox( 'test_sandbox --user_test=./t/custom_user_pwd.sb.pl', 6); MySQL-Sandbox-3.1.04/t/13_innodb_plugin_install.t000644 000765 000024 00000000347 12566053633 021564 0ustar00gmaxstaff000000 000000 use strict; use warnings; use lib './t'; use Test_Helper; use MySQL::Sandbox; confirm_version('5.1.6','5.1.99'); find_plugindir('5.1.40', '5.1.73'); test_sandbox( 'test_sandbox --user_test=./t/innodb_plugin_install.sb.pl', 16); MySQL-Sandbox-3.1.04/t/14_semi_synch_plugin_install.t000644 000765 000024 00000000513 12576721401 022444 0ustar00gmaxstaff000000 000000 use strict; use warnings; use lib './t'; use Test_Helper; use MySQL::Sandbox; confirm_version('5.5.1','10.1.99'); my $use_current = 0; if ($ENV{TEST_VERSION} gt '5.6') { $use_current =1; } # find_plugindir('5.5.4', '5.7.99', $use_current); test_sandbox( 'test_sandbox --user_test=./t/semi_synch_plugin_install.sb.pl', 9); MySQL-Sandbox-3.1.04/t/15_user_privileges.t000644 000765 000024 00000000256 12566053633 020417 0ustar00gmaxstaff000000 000000 use lib './t'; use Test_Helper; warn "# Using version <$ENV{TEST_VERSION}>\n" if $ENV{SBDEBUG}; test_sandbox( 'test_sandbox --user_test=./t/user_privileges.sb.pl', 50, 0); MySQL-Sandbox-3.1.04/t/16_replication_options.t000644 000765 000024 00000000155 12566053633 021273 0ustar00gmaxstaff000000 000000 use lib './t'; use Test_Helper; test_sandbox( 'test_sandbox --user_test=./t/replication_options.sb.pl', 21); MySQL-Sandbox-3.1.04/t/17_replication_flow.t000644 000765 000024 00000000116 12566053633 020545 0ustar00gmaxstaff000000 000000 use lib './t'; use Test_Helper; test_sandbox( "./t/replication_flow.sh", 24); MySQL-Sandbox-3.1.04/t/18_force_creation.t000644 000765 000024 00000000154 12566053633 020172 0ustar00gmaxstaff000000 000000 use lib './t'; use Test_Helper; test_sandbox( 'test_sandbox --tests=user --user_test=./t/force.sb.pl', 11); MySQL-Sandbox-3.1.04/t/19_replication_gtid.t000644 000765 000024 00000000275 12566053633 020535 0ustar00gmaxstaff000000 000000 use strict; use warnings; use lib './t'; use Test_Helper; use MySQL::Sandbox; confirm_version('5.6.6','5.7.99'); test_sandbox( 'test_sandbox --user_test=./t/replication_gtid.sb.pl', 16); MySQL-Sandbox-3.1.04/t/20_add_option.t000644 000765 000024 00000000222 12566053633 017315 0ustar00gmaxstaff000000 000000 use strict; use warnings; use lib './t'; use Test_Helper; use MySQL::Sandbox; test_sandbox( 'test_sandbox --user_test=./t/add_option.sb.pl', 6); MySQL-Sandbox-3.1.04/t/add_option.sb.pl000644 000765 000024 00000002344 12566053633 017576 0ustar00gmaxstaff000000 000000 # Test for add_option script # my $TEST_VERSION = $ENV{TEST_VERSION}; ok_exec ( { command => "make_sandbox $TEST_VERSION -- --no_confirm --sandbox_directory=single_server", expected => "sandbox server started", msg => "server 1 started", dir_name => 'single_server installed', }); ok ( -x "$sandbox_home/single_server/add_option", "script add_option is installed"); ok_exec({ command => "$sandbox_home/single_server/add_option key-buffer-size=25M", expected => 'ok', msg => 'key buffer size option installed', }); ok_sql({ path => "$sandbox_home/single_server", query => "show variables like 'key_buffer_size'", expected => '26214400', msg => 'got right buffer size (25M)', }); my $is_in_my_cnf = qx( grep 'key.buffer.size=25M' "$sandbox_home/single_server/my.sandbox.cnf"); ok ($is_in_my_cnf && ($is_in_my_cnf =~ /key.buffer.size/), "option key_buffer_size is in configuration file"); ok_exec( { command => "sbtool -o delete -s $sandbox_home/single_server", expected => 'has been removed', msg => "single_server removed" }); MySQL-Sandbox-3.1.04/t/check_replication.sb000644 000765 000024 00000001274 12566053633 020513 0ustar00gmaxstaff000000 000000 # # Example of how to check # replication with a user defined test file # shell: command = make_replication_sandbox --verbose --replication_directory=rsandbox_XXXX $TEST_VERSION expected = replication directory installed msg = replication started sql: path = $SANDBOX_HOME/rsandbox_XXXX/master query = create table test.t1 (i int); show tables from test expected = t1 msg = table created on master sql: path = $SANDBOX_HOME/rsandbox_XXXX/node1 query = show tables from test expected = t1 msg = table replicated on slave1 shell: command = $SANDBOX_HOME/rsandbox_XXXX/stop_all expected = OK msg = replication stopped MySQL-Sandbox-3.1.04/t/check_single_server.sb000644 000765 000024 00000003004 12566053633 021042 0ustar00gmaxstaff000000 000000 # This is a sample user defined test # that you can run using test_sandbox # # There are two kind of tests: shell and sql # the test type is defined by a keyword # followed by a colon. # The 'shell' test requires a 'command', which is # passed to a shell. # The 'expected' label is a string that you # expect to find within the shell output. # If you don't expect anything, you can just # say "expected = OK", meaning that you will # be satisfied with a ZERO exit code reported # by the operating system. # The 'msg' is the description of the test # that is shown to you when the test runs. shell: command = make_sandbox $TEST_VERSION -- --no_confirm --sandbox_directory=msb_XXXX expected = sandbox server started msg = sandbox creation # The 'sql' test requires a 'path', which is the # place where the test engine expects to find a # 'use' script. # The 'query' is passed to the above mentioned script # and the output is captured for further processing. # The 'expected' parameter is a string that you want # to find in the query output. # The 'msg' parameter is like the one used with the # 'shell' test. sql: path = $SANDBOX_HOME/msb_XXXX query = select 10 * 10 expected = 100 msg = checking database response # All strings starting with a $ are expanded to their # corresponding environment variables. # For example, if $SANDBOX_HOME is /home/sb/tests, # the line below will expand to # command = /home/sb/tests/msb_5_1_30/stop shell: command = $SANDBOX_HOME/msb_XXXX/stop expected = OK msg = stopped MySQL-Sandbox-3.1.04/t/custom_user_pwd.sb.pl000644 000765 000024 00000001722 12566053633 020677 0ustar00gmaxstaff000000 000000 my $dir_name = 'msb_XXXX'; my $ver = '5.5.31'; my $TEST_VERSION = $ENV{TEST_VERSION} || $ver; my @users = ( 'newuser@127.0.0.1', 'newuser', ); for my $user (@users) { my $custom_user_name= $user; my $custom_password= 'newpassword'; ok_exec( { command => "make_sandbox $TEST_VERSION -- " ." --no_confirm " ." --sandbox_directory=$dir_name " ." --db_user=$custom_user_name " ." --db_password=$custom_password ", expected => 'sandbox server started', msg => "custom server started" }); $ENV{MYCLIENT_OPTIONS} = '-h 127.0.0.1'; ok_sql({ path => "$sandbox_home/$dir_name", query => "SELECT 10 * 10", expected => "100", msg => 'server is accessible', }); # $ENV{MYCLIENT_OPTIONS} = ''; ok_exec( { command => "sbtool -o delete -s $sandbox_home/$dir_name ", expected => 'has been removed', msg => "$dir_name removed" }); } MySQL-Sandbox-3.1.04/t/force.sb.pl000644 000765 000024 00000003136 12566053633 016554 0ustar00gmaxstaff000000 000000 # # test for installation with --force option # my $TEST_VERSION = $ENV{TEST_VERSION}; my ($bare_version, $version) = get_bare_version ($TEST_VERSION); my $SANDBOX_HOME= $ENV{SANDBOX_HOME} || "$ENV{HOME}/sandboxes"; ok_exec({ command => "make_sandbox $TEST_VERSION -- --sandbox_port=8000 --no_confirm", expected => 'sandbox server started', msg => 'server 1 started', }); ok_sql({ path => "$SANDBOX_HOME/msb_${version}/", query => "create schema db1; show schemas", expected => 'db1', msg => 'db1 schema was created', }); ok_exec({ command => "make_sandbox $TEST_VERSION -- --sandbox_port=8000 --no_confirm 2>&1 || echo 1", expected => [ 'already exists', 'not specified', 'Installation halted' ], msg => 'Server installation denied without --force', }); ok_exec({ command => "make_sandbox $TEST_VERSION -- --sandbox_port=8000 --no_confirm --force", expected => 'sandbox server started', msg => 'Same sandbox installation with --force is accepted', }); ok_sql({ path => "$SANDBOX_HOME/msb_${version}/", query => "show variables like 'port'", expected => '8000', msg => 'right port on server 1', }); ok( -d "$SANDBOX_HOME/msb_$version/old_data", "old_data was created."); ok( -d "$SANDBOX_HOME/msb_$version/old_data/db1", "db1 schema was preserved in the old datadir."); ok( ! -d "$SANDBOX_HOME/msb_$version/data/db1", "db1 schema is not in the new datadir."); ok_exec ({ command => "sbtool -o delete -s $SANDBOX_HOME/msb_${version}/", expected => 'has been removed', msg => 'server 1 stopped and removed', }); MySQL-Sandbox-3.1.04/t/group_port_checking.sb000644 000765 000024 00000005223 12566053633 021076 0ustar00gmaxstaff000000 000000 # # test for replication and group sandbox port checking # # DEPRECATED : see group_port_checking.sb.pl shell: command = make_multiple_sandbox --sandbox_base_port=8000 5.5.31 expected = group directory installed msg = group 1 started sql: path = $SANDBOX_HOME/multi_msb_5_5_31/node1 query = show variables like 'port' expected = 8001 msg = right port on node1 sql: path = $SANDBOX_HOME/multi_msb_5_5_31/node2 query = show variables like 'port' expected = 8002 msg = right port on node2 shell: #command = make_multiple_sandbox --verbose --sandbox_base_port=8000 --group_directory=gsb --check_base_port 5.5.31 command = make_multiple_sandbox --sandbox_base_port=8000 --group_directory=gsb --check_base_port 5.5.31 expected = group directory installed msg = group 2 started sql: path = $SANDBOX_HOME/gsb/node1 query = show variables like 'port' expected = 8005 msg = right port on node1 (after check) sql: path = $SANDBOX_HOME/gsb/node2 query = show variables like 'port' expected = 8006 msg = right port on node2 (after check) shell: command = make_replication_sandbox --sandbox_base_port=6000 5.5.31 expected = replication directory installed msg = replication started sql: path = $SANDBOX_HOME/rsandbox_5_5_31/master query = show variables like 'port' expected = 6000 msg = right port on master sql: path = $SANDBOX_HOME/rsandbox_5_5_31/node1 query = show variables like 'port' expected = 6001 msg = right port on node1 shell: command = make_replication_sandbox --sandbox_base_port=6000 --replication_directory=rsb --check_base_port 5.5.31 expected = replication directory installed msg = replication started sql: path = $SANDBOX_HOME/rsb/master query = show variables like 'port' expected = 6003 msg = right port on master (after check) sql: path = $SANDBOX_HOME/rsb/node1 query = show variables like 'port' expected = 6004 msg = right port on node1 (after check) shell: command = sbtool -o delete -s $SANDBOX_HOME/rsandbox_5_5_31/ expected = has been removed msg = replication 1 stopped and removed shell: command = sbtool -o delete -s $SANDBOX_HOME/rsb/ expected = has been removed msg = replication 2 stopped and removed shell: command = sbtool -o delete -s $SANDBOX_HOME/multi_msb_5_5_31 expected = has been removed msg = group 1 stopped and removed shell: command = sbtool -o delete -s $SANDBOX_HOME/gsb/ expected = has been removed msg = group 2 stopped and removed MySQL-Sandbox-3.1.04/t/group_port_checking.sb.pl000644 000765 000024 00000006037 12566053633 021514 0ustar00gmaxstaff000000 000000 # # test for replication and group sandbox port checking # my $TEST_VERSION = $ENV{TEST_VERSION}; my ($bare_version, $version) = get_bare_version ($TEST_VERSION); my $SANDBOX_HOME= $ENV{SANDBOX_HOME} || "$ENV{HOME}/sandboxes"; ok_exec ({ command => "make_multiple_sandbox --sandbox_base_port=8000 $TEST_VERSION", expected => "group directory installed", msg => "group 1 started", }); ok_sql({ path => "$SANDBOX_HOME/multi_msb_$version/node1", query => "show variables like 'port'", expected => "8001", msg => "right port on node1", }); ok_sql({ path => "$SANDBOX_HOME/multi_msb_$version/node2", query => "show variables like 'port'", expected => "8002", msg => "right port on node2", }); ok_exec ({ command => "make_multiple_sandbox --sandbox_base_port=8000 --group_directory=gsb --check_base_port $TEST_VERSION", expected => "group directory installed", msg => "group 2 started", }); ok_sql({ path => "$SANDBOX_HOME/gsb/node1", query => "show variables like 'port'", expected => "8005", msg => "right port on node1 (after check)", }); ok_sql({ path => "$SANDBOX_HOME/gsb/node2", query => "show variables like 'port'", expected => "8006", msg => "right port on node2 (after check)", }); ok_exec ({ command => "make_replication_sandbox --sandbox_base_port=6000 $TEST_VERSION", expected => "replication directory installed", msg => "replication started", }); ok_sql({ path => "$SANDBOX_HOME/rsandbox_$version/master", query => "show variables like 'port'", expected => "6000", msg => "right port on master", }); ok_sql({ path => "$SANDBOX_HOME/rsandbox_$version/node1", query => "show variables like 'port'", expected => "6001", msg => "right port on node1", }); ok_exec ({ command => "make_replication_sandbox --sandbox_base_port=6000 --replication_directory=rsb --check_base_port $TEST_VERSION", expected => "replication directory installed", msg => "replication started", }); ok_sql({ path => "$SANDBOX_HOME/rsb/master", query => "show variables like 'port'", expected => "6003", msg => "right port on master (after check)", }); ok_sql({ path => "$SANDBOX_HOME/rsb/node1", query => "show variables like 'port'", expected => "6004", msg => "right port on node1 (after check)", }); ok_exec ({ command => "sbtool -o delete -s $SANDBOX_HOME/rsandbox_$version/", expected => "has been removed", msg => "replication 1 stopped and removed", }); ok_exec ({ command => "sbtool -o delete -s $SANDBOX_HOME/rsb/", expected => "has been removed", msg => "replication 2 stopped and removed", }); ok_exec ({ command => "sbtool -o delete -s $SANDBOX_HOME/multi_msb_$version", expected => "has been removed", msg => "group 1 stopped and removed", }); ok_exec ({ command => "sbtool -o delete -s $SANDBOX_HOME/gsb/", expected => "has been removed", msg => "group 2 stopped and removed", }); MySQL-Sandbox-3.1.04/t/innodb_plugin_install.sb.pl000644 000765 000024 00000011062 12566053633 022030 0ustar00gmaxstaff000000 000000 # Test for Innodb plugin installation # # my $TEST_VERSION = $ENV{TEST_VERSION}; my ($bare_version, $version) = get_bare_version ($TEST_VERSION); my $plugindir = $ENV{SB_PLUGIN_DIR} or die "expected environment variable \$SB_PLUGIN_DIR not set\n"; my %plugin_version = ( '5.1.40' => '1.0.4', '5.1.41' => '1.0.5', '5.1.42' => '1.0.6', '5.1.43' => '1.0.6', '5.1.44' => '1.0.6', '5.1.45' => '1.0.6', '5.1.45' => '1.0.6', '5.1.46' => '1.0.7', '5.1.47' => '1.0.8', '5.1.48' => '1.0.9', '5.1.57' => '1.0.16', '5.1.63' => '1.0.17', '5.1.73' => '5.1.73', ); my $skip_tests=0; unless (defined $plugin_version{$TEST_VERSION}) { warn "# No plugin info found for version $TEST_VERSION\n"; $plugin_version{$TEST_VERSION} = ""; $skip_tests=1; } my @test_sb = ( { type => 'exec', command => "make_sandbox $TEST_VERSION -- --no_confirm " . "--sandbox_directory=single_server", expected => "sandbox server started", msg => "single server started", }, { type => 'exec', command => "make_replication_sandbox " . "--replication_directory=group_server $TEST_VERSION ", expected => 'replication directory installed', msg => 'group directory started', }, { type => 'exec', command => "sbtool -o plugin " . " --plugin=innodb" . " -s $sandbox_home/single_server ", expected => ['innodb_version', $plugin_version{$TEST_VERSION}], msg => 'innodb plugin installed on single_server', }, { type => 'sql', path => "$sandbox_home/single_server", query => "create table test.t1 (i int) engine=innodb " . "ROW_FORMAT=COMPRESSED KEY_BLOCK_SIZE=8;" . " show create table test.t1 ", expected => ['innodb', 'compressed'], msg => 'innodb plugin working on single_server', }, { type => 'exec', command => "sbtool -o plugin " . " --plugin=innodb" . " -s $sandbox_home/group_server ", expected => ['innodb_version', $plugin_version{$TEST_VERSION} ], msg => 'innodb plugin installed on group_server', }, { type => 'sql', path => "$sandbox_home/group_server/master", query => "create table test.t1 (i int) engine=innodb " . "ROW_FORMAT=COMPRESSED KEY_BLOCK_SIZE=8;" . " show create table test.t1 ", expected => ['innodb', 'compressed'], msg => 'innodb plugin working on group_server/master', }, { type => 'sleep', how_much => 2}, { type => 'sql', path => "$sandbox_home/group_server/node1", query => " show create table test.t1 ", expected => ['innodb', 'compressed'], msg => 'innodb plugin working on group_server/node1', }, { type => 'sql', path => "$sandbox_home/group_server/node2", query => " show create table test.t1 ", expected => ['innodb', 'compressed'], msg => 'innodb plugin working on group_server/node2', }, { type => 'exec', command => "$sandbox_home/single_server/stop", expected => "ok", msg => "single server stopped", }, { type => 'exec', command => "$sandbox_home/group_server/stop_all", expected => "ok", msg => "group server stopped", }, ); for my $test (@test_sb) { if ($skip_tests) { my $msg = $test->{msg} || ''; my $expected = $test->{expected} || ''; if ($expected) { if (ref $expected) { for my $e (@$expected) { print "ok - skipped - $msg ($e)\n"; } } else { print "ok - skipped - $msg ($expected)\n"; } } } else { if ($test->{type} eq 'exec') { ok_exec( $test); } elsif ($test->{type} eq 'sql') { ok_sql($test); } elsif ($test->{type} eq 'sleep') { sleep($test->{how_much} || 1 ); } else { die "unrecognized type\n"; } } } MySQL-Sandbox-3.1.04/t/replication_flow.sh000755 000765 000024 00000001743 12566053633 020417 0ustar00gmaxstaff000000 000000 #!/bin/bash sandbox_home=$SANDBOX_HOME replication_dir=repl_deployment function ok_equal { fact="$1" expected="$2" msg="$3" if [ "$fact" == "$expected" ] then echo -n "ok" else echo -n "not ok" fi echo " - $msg"; } make_replication_sandbox --replication_directory=$replication_dir $TEST_VERSION ok_equal $? 0 "Replication directory created" sleep 1 $sandbox_home/$replication_dir/test_replication ok_equal $? 0 "Replication test was successful" sbtool -o delete -s $sandbox_home/$replication_dir ok_equal $? 0 "Regular replication directory $replication_dir removed" make_replication_sandbox --circular=3 --replication_directory=$replication_dir $TEST_VERSION ok_equal $? 0 'circular replication installed' sleep 1 $sandbox_home/$replication_dir/test_replication ok_equal $? 0 "Replication test was successful" sbtool -o delete -s $sandbox_home/$replication_dir ok_equal $? 0 "Circular replication directory $replication_dir removed" MySQL-Sandbox-3.1.04/t/replication_gtid.sb.pl000644 000765 000024 00000006014 12566053633 020774 0ustar00gmaxstaff000000 000000 # # Test GTID enabling # Requires MySQL 5.6 - 5.7+ # my $TEST_VERSION = $ENV{TEST_VERSION}; my ($version, $name_version) = get_bare_version($TEST_VERSION); my $replication_dir = "rsandbox_$name_version"; ok_exec({ command => "make_replication_sandbox $TEST_VERSION ", expected => 'replication directory installed', msg => 'replication directory installed', }); ok( (-f "$sandbox_home/$replication_dir/enable_gtid" ), "file enable_gtid found "); my $result = qx( $sandbox_home/$replication_dir/enable_gtid ); ok( $? == 0 , 'enable_gtid ran without errors'); ok( $result && ($result =~ /# option 'gtid_mode=ON' added to \w+ configuration file/), "enable_gtid added options successfully"); ok_sql({ path => "$sandbox_home/$replication_dir/master", query => 'select @@global.gtid_mode', expected => 'ON', msg => 'Master GTID is enabled', }); ok_sql({ path => "$sandbox_home/$replication_dir/master", query => 'select @@global.server_uuid', expected => '1111-111111111111', msg => 'Master UUID was modified', }); ok_sql({ path => "$sandbox_home/$replication_dir/node1", query => 'select @@global.server_uuid', expected => '2222-222222222222', msg => 'slave 1 UUID was modified', }); ok_sql({ path => "$sandbox_home/$replication_dir/node2", query => 'select @@global.server_uuid', expected => '3333-333333333333', msg => 'slave 2 UUID was modified', }); ok_sql({ path => "$sandbox_home/$replication_dir/node1", query => 'select @@global.gtid_mode', expected => 'ON', msg => 'Slave1 GTID is enabled', }); ok_sql({ path => "$sandbox_home/$replication_dir/master", query => "create table test.t1 (id int not null primary key); show tables from test", expected => 't1', msg => 'Master created a table', }); ok_sql({ path => "$sandbox_home/$replication_dir/master", query => "insert into test.t1 values(12345); select * from test.t1", expected => '12345', msg => 'Master inserted a row', }); sleep 2; ok_sql({ path => "$sandbox_home/$replication_dir/node1", query => "show tables from test", expected => 't1', msg => 'slave replicated the table', }); ok_sql({ path => "$sandbox_home/$replication_dir/node1", query => "select * from test.t1", expected => '12345', msg => 'Slave retrieved a row', }); ok_sql({ path => "$sandbox_home/$replication_dir/master", query => 'select @@global.gtid_executed', expected => '1111-111111111111:1-2', msg => 'Master has produced a GTID', }); ok_sql({ path => "$sandbox_home/$replication_dir/node1", query => 'select @@global.gtid_executed', expected => '1111-111111111111:1-2', msg => 'Slave has retrieved a GTID', }); ok_exec( { command => "sbtool -o delete -s $sandbox_home/$replication_dir ", expected => 'has been removed', msg => "$replication_dir removed" }); MySQL-Sandbox-3.1.04/t/replication_options.sb.pl000644 000765 000024 00000011363 12566053633 021543 0ustar00gmaxstaff000000 000000 # # Test replication parameters. # You can affect the replication installation with some # command line options # * --master_options only master # * --slave_options only slaves # * --node_options all nodes, master and slaves # my $TEST_VERSION = $ENV{TEST_VERSION}; my ($version, $name_version) = get_bare_version($TEST_VERSION); my $replication_dir = "rsandbox_$name_version"; $ENV{MASTER_OPTIONS} = ''; $ENV{SLAVE_OPTIONS} = ''; $ENV{NODE_OPTIONS} = ''; my $master_options = '-c key-buffer-size=20M'; my $slave_options = '-c key-buffer-size=25M'; my $node_options = '-c max_allowed_packet=3M'; my $command_line_options = "--master_options='$master_options' " . "--slave_options='$slave_options' " . "--node_options='$node_options' $TEST_VERSION "; ok_exec({ command => "make_replication_sandbox $command_line_options $TEST_VERSION ", expected => 'replication directory installed', msg => 'replication directory installed', }); sleep 2; ok_sql({ path => "$sandbox_home/$replication_dir/master", query => "show variables like 'key_buffer_size'", expected => '20971520', msg => 'master key buffer (20M)', }); ok_sql({ path => "$sandbox_home/$replication_dir/master", query => "show variables like 'max_allowed_packet'", expected => '3145728', msg => 'master max allowed packet (3M)', }); ok_sql({ path => "$sandbox_home/$replication_dir/node1", query => "show variables like 'max_allowed_packet'", expected => '3145728', msg => 'node 1 max allowed packet (3M)', }); ok_sql({ path => "$sandbox_home/$replication_dir/node2", query => "show variables like 'max_allowed_packet'", expected => '3145728', msg => 'node 2 max allowed packet (3M)', }); ok_sql({ path => "$sandbox_home/$replication_dir/node1", query => "show variables like 'key_buffer_size'", expected => '26214400', msg => 'slave 1 key buffer (25M)', }); ok_sql({ path => "$sandbox_home/$replication_dir/node2", query => "show variables like 'key_buffer_size'", expected => '26214400', msg => 'slave 2 key buffer (25M)', }); ok_exec( { command => "sbtool -o delete -s $sandbox_home/$replication_dir ", expected => 'has been removed', msg => "$replication_dir removed" }); # Test --master and --slaveof my $master_extra_options=''; # workaround for Bug#77732 added to low_level_make_sandbox #if ($TEST_VERSION =~ /5\.7\.8/) #{ # $master_extra_options .= ' -c show_compatibility_56=on ' #} ok_exec({ command => "make_sandbox $TEST_VERSION -- --master --sandbox_directory=msb_master --sandbox_port=8000 --no_confirm $master_extra_options", expected => 'sandbox server started', msg => 'sandbox master installed', }); sleep 2; ok_exec({ command => "make_sandbox $TEST_VERSION -- --no_confirm --sandbox_port=8001 --sandbox_directory=msb_slave --slaveof='master_port=8000' ", expected => 'sandbox server started', msg => 'sandbox master installed', }); sleep 2; ok_sql({ path => "$sandbox_home/msb_master/", query => "show variables like 'log_bin'", expected => 'ON', msg => 'master binlog', }); ok_sql({ path => "$sandbox_home/msb_master/", query => "show variables like 'server_id'", expected => '8000', msg => 'master server ID', }); ok_sql({ path => "$sandbox_home/msb_slave/", query => "show variables like 'server_id'", expected => '8001', msg => 'slave server ID', }); ok_sql({ path => "$sandbox_home/msb_slave/", query => "show slave status \\G", expected => ['Slave_IO_Running: Yes', 'Slave_SQL_Running: Yes'], msg => 'slave server ID', }); ok_exec( { command => "sbtool -o delete -s $sandbox_home/msb_master ", expected => 'has been removed', msg => "msb_master removed" }); ok_exec( { command => "sbtool -o delete -s $sandbox_home/msb_slave ", expected => 'has been removed', msg => "msb_slave removed" }); # testing --high_performance # ok_exec({ command => "make_sandbox $TEST_VERSION -- --high_performance --sandbox_directory=msb_hp --sandbox_port=8000 --no_confirm", expected => 'sandbox server started', msg => 'sandbox hp installed', }); sleep 2; ok_sql({ path => "$sandbox_home/msb_hp/", query => "show variables like 'innodb%'", expected => ['innodb_buffer_pool_size\s*536870912', 'innodb_flush_method\s*O_DIRECT'], msg => 'high performance options', }); ok_exec( { command => "sbtool -o delete -s $sandbox_home/msb_hp ", expected => 'has been removed', msg => "msb_hp removed" }); MySQL-Sandbox-3.1.04/t/replication_parameters.sb.pl000644 000765 000024 00000004757 12566053633 022224 0ustar00gmaxstaff000000 000000 # # Test replication parameters. # You can affect the replication installation with some # environment variables # * MASTER_OPTIONS only master # * SLAVE_OPTIONS only slaves # * NODE_OPTIONS all nodes, master and slaves # # Options passed through these variables follow the # same rule used for make_sandbox and low_level_make_sandbox # "-c option=value" # my $TEST_VERSION = $ENV{TEST_VERSION}; my $expected_gtid = 'does not exist'; my ($version, $name_version) = get_bare_version($TEST_VERSION); if ($version ge '5.6') { $expected_gtid = 'exists'; } my $replication_dir = "rsandbox_$name_version"; $ENV{MASTER_OPTIONS} = '-c key-buffer-size=20M'; $ENV{SLAVE_OPTIONS} = '-c key-buffer-size=25M'; $ENV{NODE_OPTIONS} = '-c max_allowed_packet=3M'; ok_exec({ command => "make_replication_sandbox $TEST_VERSION ", expected => 'replication directory installed', msg => 'replication directory installed', }); sleep 2; ok_sql({ path => "$sandbox_home/$replication_dir/master", query => "show variables like 'key_buffer_size'", expected => '20971520', msg => 'master key buffer (20M)', }); ok_sql({ path => "$sandbox_home/$replication_dir/master", query => "show variables like 'max_allowed_packet'", expected => '3145728', msg => 'master max allowed packet (3M)', }); ok_sql({ path => "$sandbox_home/$replication_dir/node1", query => "show variables like 'max_allowed_packet'", expected => '3145728', msg => 'node 1 max allowed packet (3M)', }); ok_sql({ path => "$sandbox_home/$replication_dir/node2", query => "show variables like 'max_allowed_packet'", expected => '3145728', msg => 'node 2 max allowed packet (3M)', }); ok_sql({ path => "$sandbox_home/$replication_dir/node1", query => "show variables like 'key_buffer_size'", expected => '26214400', msg => 'slave 1 key buffer (25M)', }); ok_sql({ path => "$sandbox_home/$replication_dir/node2", query => "show variables like 'key_buffer_size'", expected => '26214400', msg => 'slave 2 key buffer (25M)', }); my $gtid_exists = 'does not exist'; if (-f "$sandbox_home/$replication_dir/enable_gtid" ) { $gtid_exists = 'exists'; } ok $gtid_exists eq $expected_gtid, "file enable_gtid $expected_gtid "; ok_exec( { command => "sbtool -o delete -s $sandbox_home/$replication_dir ", expected => 'has been removed', msg => "$replication_dir removed" }); MySQL-Sandbox-3.1.04/t/semi_synch_plugin_install.sb.pl000644 000765 000024 00000006742 12576721401 022725 0ustar00gmaxstaff000000 000000 # Test for semi-synch plugin installation # # my $TEST_VERSION = $ENV{TEST_VERSION}; my ($bare_version, $version, $major,$minor, $rev) = get_bare_version ($TEST_VERSION); my $reference_schema = 'information_schema'; my $additional_5_7_options=''; # Starting with MySQL 5.7.8, information_schema.global_* tables # are now in performance_schema if ( (($major ==5) && ($minor > 7) ) or ( ($major ==5) && ($minor == 7) && ($rev >= 8) ) ) { # $additional_5_7_options = "--node_options=' -c show_compatibility_56=on'"; $reference_schema='performance_schema'; } #my $plugindir = $ENV{SB_PLUGIN_DIR} # or die "expected environment variable \$SB_PLUGIN_DIR not set\n"; # print "<$TEST_VERSION>";exit; my @test_sb = ( { type => 'exec', command => "make_replication_sandbox " . "--replication_directory=group_server $TEST_VERSION $additional_5_7_options ", expected => 'replication directory installed', msg => 'group directory started', }, { type => 'exec', command => "sbtool -o plugin " . " --plugin=semisynch" . " -s $sandbox_home/group_server ", expected => ['@@rpl_semi_sync_master_enabled', '@@rpl_semi_sync_slave_enabled'], msg => 'semisynch plugin installed on group_server', }, { type => 'sql', path => "$sandbox_home/group_server/master", query => "create table test.t1 (i int);" . "show tables from test", expected => 't1', msg => 'table created on master' }, { type => 'sql', path => "$sandbox_home/group_server/master", query => "select variable_value " . "from $reference_schema . global_status " . "where variable_name = 'Rpl_semi_sync_master_yes_tx'", expected => 1, msg => 'semi-synch plugin working on group_server/master - 1', }, { type => 'sql', path => "$sandbox_home/group_server/master", query => "select variable_value " . "from $reference_schema . global_status " . "where variable_name = 'Rpl_semi_sync_master_no_tx'", expected => 0, msg => 'semi-synch plugin working on group_server/master - 2', }, { type => 'sleep', how_much => 2}, { type => 'sql', path => "$sandbox_home/group_server/node1", query => " show tables from test ", expected => 't1', msg => 'replication working on group_server/node1', }, { type => 'sql', path => "$sandbox_home/group_server/node2", query => " show tables from test ", expected => 't1', msg => 'replication working on group_server/node2', }, { type => 'exec', command => "$sandbox_home/group_server/stop_all", expected => "ok", msg => "group server stopped", }, ); for my $test (@test_sb) { if ($test->{type} eq 'exec') { ok_exec( $test); } elsif ($test->{type} eq 'sql') { ok_sql($test); } elsif ($test->{type} eq 'sleep') { sleep($test->{how_much} || 1 ); } else { die "unrecognized type\n"; } } MySQL-Sandbox-3.1.04/t/single_port_checking.sb000644 000765 000024 00000001743 12566053633 021226 0ustar00gmaxstaff000000 000000 # # test for replication and group sandbox port checking # # # DEPRECATED : replaced by single_port_checking.sb.pl # shell: command = make_sandbox 5.5.31 -- --sandbox_port=8000 --no_confirm expected = sandbox server started msg = server 1 started shell: command = make_sandbox 5.5.31 -- --sandbox_port=8000 --check_port --no_confirm expected = sandbox server started msg = server 2 started sql: path = $SANDBOX_HOME/msb_5_5_31/ query = show variables like 'port' expected = 8000 msg = right port on server 1 sql: path = $SANDBOX_HOME/msb_5_5_31_a query = show variables like 'port' expected = 8001 msg = right port on server 2 shell: command = sbtool -o delete -s $SANDBOX_HOME/msb_5_5_31/ expected = has been removed msg = server 1 stopped and removed shell: command = sbtool -o delete -s $SANDBOX_HOME/msb_5_5_31_a expected = has been removed msg = server 2 stopped and removed MySQL-Sandbox-3.1.04/t/single_port_checking.sb.pl000644 000765 000024 00000002354 12566053633 021637 0ustar00gmaxstaff000000 000000 # # test for replication and group sandbox port checking # my $TEST_VERSION = $ENV{TEST_VERSION}; my ($bare_version, $version) = get_bare_version ($TEST_VERSION); my $SANDBOX_HOME= $ENV{SANDBOX_HOME} || "$ENV{HOME}/sandboxes"; ok_exec({ command => "make_sandbox $TEST_VERSION -- --sandbox_port=8000 --no_confirm", expected => 'sandbox server started', msg => 'server 1 started', }); ok_exec({ command => "make_sandbox $TEST_VERSION -- --sandbox_port=8000 --check_port --no_confirm", expected => 'sandbox server started', msg => 'server 2 started', }); ok_sql({ path => "$SANDBOX_HOME/msb_${version}/", query => "show variables like 'port'", expected => '8000', msg => 'right port on server 1', }); ok_sql({ path => "$SANDBOX_HOME/msb_${version}_a", query => "show variables like 'port'", expected => "8001", msg => 'right port on server 2', }); ok_exec ({ command => "sbtool -o delete -s $SANDBOX_HOME/msb_${version}/", expected => 'has been removed', msg => 'server 1 stopped and removed', }); ok_exec({ command => "sbtool -o delete -s $SANDBOX_HOME/msb_${version}_a", expected => "has been removed", msg => "server 2 stopped and removed", }); MySQL-Sandbox-3.1.04/t/start_restart_arguments.sb000644 000765 000024 00000010036 12566053633 022027 0ustar00gmaxstaff000000 000000 # Test for drill-down start and restart parameters # Obsolete. Replaced by start_restart_arguments.sb.pl # # single server # shell: command = make_sandbox $TEST_VERSION -- --no_confirm --sandbox_directory=single_server expected = sandbox server started msg = server 1 started shell: command = $SANDBOX_HOME/stop_all expected = OK msg = all servers stopped shell: command = $SANDBOX_HOME/start_all --key-buffer-size=20M expected = OK msg = all servers started shell: command = $SANDBOX_HOME/use_all "show variables like 'key_buffer_size' " expected = 20971520 msg = got right buffer size (20M) shell: command = $SANDBOX_HOME/restart_all --key-buffer-size=25M expected = OK msg = all servers restarted shell: command = $SANDBOX_HOME/use_all "show variables like 'key_buffer_size' " expected = 26214400 msg = got right buffer size (25M) shell: command = sbtool -o delete -s $SANDBOX_HOME/single_server expected = has been removed msg = single_server stopped and removed # # group directory # shell: command = make_multiple_sandbox $TEST_VERSION --group_directory=group_server expected = group directory installed msg = group directory started shell: command = $SANDBOX_HOME/stop_all expected = OK msg = all servers stopped shell: command = $SANDBOX_HOME/start_all --key-buffer-size=20M expected = OK msg = all servers started shell: command = $SANDBOX_HOME/use_all "show variables like 'key_buffer_size' " expected = 20971520 msg = got right buffer size (20M) shell: command = $SANDBOX_HOME/restart_all --key-buffer-size=25M expected = OK msg = all servers restarted shell: command = $SANDBOX_HOME/use_all "show variables like 'key_buffer_size' " expected = 26214400 msg = got right buffer size (25M) shell: command = sbtool -o delete -s $SANDBOX_HOME/group_server expected = has been removed msg = group server stopped and removed # # replication directory # shell: command = make_replication_sandbox $TEST_VERSION --replication_directory=replication_server expected = replication directory installed msg = replication sandbox started shell: command = $SANDBOX_HOME/stop_all expected = OK msg = all servers stopped shell: command = $SANDBOX_HOME/start_all --key-buffer-size=20M expected = OK msg = all servers started shell: command = $SANDBOX_HOME/use_all "show variables like 'key_buffer_size' " expected = 20971520 msg = got right buffer size (20M) shell: command = $SANDBOX_HOME/restart_all --key-buffer-size=25M expected = OK msg = all servers restarted shell: command = $SANDBOX_HOME/use_all "show variables like 'key_buffer_size' " expected = 26214400 msg = got right buffer size (25M) shell: command = sbtool -o delete -s $SANDBOX_HOME/replication_server expected = has been removed msg = replication server stopped and removed # # circular replication directory # shell: command = make_replication_sandbox $TEST_VERSION --circular=3 --replication_directory=replication_server expected = group directory installed msg = circular replication sandbox started shell: command = $SANDBOX_HOME/stop_all expected = OK msg = all servers stopped shell: command = $SANDBOX_HOME/start_all --key-buffer-size=20M expected = OK msg = all servers started shell: command = $SANDBOX_HOME/use_all "show variables like 'key_buffer_size' " expected = 20971520 msg = got right buffer size (20M) shell: command = $SANDBOX_HOME/restart_all --key-buffer-size=25M expected = OK msg = all servers restarted shell: command = $SANDBOX_HOME/use_all "show variables like 'key_buffer_size' " expected = 26214400 msg = got right buffer size (25M) shell: command = sbtool -o delete -s $SANDBOX_HOME/replication_server expected = has been removed msg = circular replication server stopped and removed MySQL-Sandbox-3.1.04/t/start_restart_arguments.sb.pl000644 000765 000024 00000005217 12566053633 022446 0ustar00gmaxstaff000000 000000 # Test for drill-down start and restart parameters # # Creates single and multiple sandboxes, sends a "start_all" call with # parameters, and checks that the parameter was received. # my $TEST_VERSION = $ENV{TEST_VERSION}; my @test_sb = ( { command => "make_sandbox $TEST_VERSION -- --no_confirm --sandbox_directory=single_server", expected => "sandbox server started", msg => "server 1 started", dir_name => 'single_server', }, { command => "make_multiple_sandbox --group_directory=group_server $TEST_VERSION ", expected => 'group directory installed', msg => 'group directory started', dir_name => 'group_server', }, { command => "make_multiple_custom_sandbox --group_directory=custom_server $TEST_VERSION ", expected => 'group directory installed', msg => 'custom directory started', dir_name => 'custom_server', }, { command => "make_replication_sandbox --replication_directory=replication_server $TEST_VERSION ", expected => 'replication directory installed', msg => 'replication directory started', dir_name => 'replication_server', }, { command => "make_replication_sandbox --circular=3 --replication_directory=replication_server $TEST_VERSION ", expected => 'group directory installed', msg => 'circular directory started', dir_name => 'replication_server', }, ); for my $test (@test_sb) { ok_exec( $test); ok_exec({ command => "$sandbox_home/stop_all", expected => 'ok', msg => 'all servers stopped', }); ok_exec({ command => "$sandbox_home/start_all --key-buffer-size=20M", expected => 'ok', msg => 'all servers started', }); ok_exec({ command => qq($sandbox_home/use_all "show variables like 'key_buffer_size'"), expected => '20971520', msg => 'got right buffer size (20M)', }); ok_exec({ command => "$sandbox_home/restart_all --key-buffer-size=25M", expected => 'ok', msg => 'all servers restarted', }); ok_exec({ command => qq($sandbox_home/use_all "show variables like 'key_buffer_size'"), expected => '26214400', msg => 'got right buffer size (25M)', }); ok_exec( { command => "sbtool -o delete -s $sandbox_home/$test->{dir_name} ", expected => 'has been removed', msg => "$test->{dir_name} removed" }); } MySQL-Sandbox-3.1.04/t/Test_Helper.pm000644 000765 000024 00000012557 12631433571 017275 0ustar00gmaxstaff000000 000000 package Test_Helper; my $test_version; BEGIN { sub skip_all { my ($msg) = @_; print "1..1\n", "ok - Skipped. $msg\n"; exit; } if ($^O =~ /^(?:mswin|win)/i) { skip_all ('This module is not for Windows'); } use MySQL::Sandbox qw/split_version/; $ENV{TEST_SANDBOX_HOME}="$ENV{PWD}/t/test_sb"; $ENV{PERL5LIB}="$ENV{PWD}/lib"; $ENV{PATH}="$ENV{PWD}/bin:$ENV{PATH}"; $ENV{TEST_VERSION} = $ENV{TEST_VERSION} || '5.6.26'; $ENV{SANDBOX_AS_ROOT} = 1; $test_version = $ENV{TEST_VERSION} ; }; use strict; use warnings; use base qw( Exporter); our @ISA= qw(Exporter); our @EXPORT_OK= qw( test_sandbox find_plugindir skip_all confirm_version); our @EXPORT = @EXPORT_OK; #sub get_version_parts #{ # my ($version) = @_; # if ($version =~ /(\d+)\.(\d+)\.(\d+)/) # { # my ($major, $minor, $rev) = ($1, $2, $3) ; # return ($major, $minor, $rev); # } # else # { # die "# version $version does not have expected components" # } #} sub confirm_version { my ($min_version, $max_version) = @_; my $will_skip =0; my ($major, $minor, $rev) = split_version($test_version); my ($major1, $minor1, $rev1) = split_version($min_version); my ($major2, $minor2, $rev2) = split_version($max_version); my $compare_test = sprintf("%05d-%05d-%05d", $major, $minor, $rev); my $compare_min = sprintf("%05d-%05d-%05d", $major1, $minor1, $rev1); my $compare_max = sprintf("%05d-%05d-%05d", $major2, $minor2, $rev2); unless (($compare_test ge $compare_min) && ($compare_test le $compare_max)) { warn "# Skipping version $test_version for this test. It is not in the required range ($min_version - $max_version)\n"; print "1..1\n"; print "ok 1 # Test version $test_version is not in the required range for this test ($min_version - $max_version)\n"; exit; } } sub test_sandbox { my ($cmd, $expected_tests, $informative) = @_; unless ($cmd) { die "command expected\n"; } unless ($expected_tests) { die "number of tests expected as second parameter\n"; } $expected_tests =~ /^\d+$/ or die "the 'expected tests' parameter must be a number \n"; ## # accepts either a bare version # (e.g. 5.0.79) # or a tarball # (e.g. $HOME/downloads/mysql-5.0.79-osx10.5-x86.tar.gz) # or the path to a directory containing binaries # (e.g. $HOME/opt/mysql/5.0.79) if ( ( -d $test_version) or (( -f $test_version ) && ($test_version =~ /\.tar\.gz$/) ) or ( -d "$ENV{HOME}/opt/mysql/$test_version")) { warn "Testing <$test_version>. " . "Please wait. This will take a few minutes\n" if $informative; print "1..$expected_tests\n"; } else { print "1..1\n"; print "ok 1 # skip - no binaries found for $test_version\n"; print " - See the README under 'TESTING' for more options.\n" if $informative; exit; } $ENV{TAP_MODE} =1; system ("$cmd --versions=$test_version "); } sub find_plugindir { my ($minimum_version, $maximum_version, $use_current) = @_; my $minimum_version_str; my $maximum_version_str; if ($minimum_version =~ /(\d+)\.(\d+)\.(\d+)/) { $minimum_version_str = sprintf('%02d-%02d-%02d', $1, $2, $3); } else { die "# Invalid minimum version provided : $minimum_version\n"; } if ($maximum_version =~ /(\d+)\.(\d+)\.(\d+)/) { $maximum_version_str = sprintf('%02d-%02d-%02d', $1, $2, $3); } else { die "# Invalid maximum version provided : $maximum_version\n"; } my $plugindir; if ( $ENV{SANDBOX_BINARY} && ( -d $ENV{SANDBOX_BINARY}) ) { # # finds the latest 5.x version # my $highest_version = ''; my @versions = (); my @dirs = sort { $b cmp $a } grep { ($_ ge $minimum_version_str) && ($_ le $maximum_version_str) } map { m{(\d)\.(\d)\.(\d+)/?$}; sprintf('%02d-%02d-%02d',$1,$2,$3) } grep { /\d+\.\d+\.\d+/ } grep { -d $_ } glob("$ENV{SANDBOX_BINARY}/*/" ) ; unless (@dirs) { skip_all("no directories found under $ENV{SANDBOX_BINARY}"); } $highest_version = $dirs[0]; if ($highest_version lt $minimum_version_str) { skip_all("no suitable version found for this test"); } my $TEST_VERSION = $ENV{TEST_VERSION} || $highest_version; # print "<@dirs> <$highest_version> <$TEST_VERSION>\n"; unless ( grep { $TEST_VERSION eq $_ } @dirs ) { #skip_all("$TEST_VERSION is not suitable for this test"); $TEST_VERSION = $highest_version unless $use_current; } warn "# Testing plugin with <$TEST_VERSION>\n"; $ENV{TEST_VERSION} = $TEST_VERSION; $plugindir = "$ENV{SANDBOX_BINARY}/$TEST_VERSION/lib/plugin"; unless ( -d $plugindir) { $plugindir = "$ENV{SANDBOX_BINARY}/$TEST_VERSION/lib/mysql/plugin"; unless ( -d $plugindir) { skip_all("Plugin directory for $TEST_VERSION not found"); } } } else { skip_all('no $SANDBOX_BINARY found'); } $ENV{'SB_PLUGIN_DIR'} = $plugindir; } 1; __END__ MySQL-Sandbox-3.1.04/t/user_privileges.sb000644 000765 000024 00000022677 12566053633 020266 0ustar00gmaxstaff000000 000000 ########################################### # checking default user privileges ########################################### # # Note: this script is broken in MySQL 5.7.6 and later # DEPRECATED: replaced by user_privileges.sb.pl shell: command = make_sandbox $TEST_VERSION -- --no_confirm --sandbox_directory=msb_XXXX expected = sandbox server started msg = sandbox creation #+-----------+-------------+-------------------------------------------+ #| host | user | password | #+-----------+-------------+-------------------------------------------+ #| localhost | root | *6C387FC3893DBA1E3BA155E74754DA6682D04747 | #| 127.% | msandbox | *6C387FC3893DBA1E3BA155E74754DA6682D04747 | #| localhost | msandbox | *6C387FC3893DBA1E3BA155E74754DA6682D04747 | #| localhost | msandbox_rw | *6C387FC3893DBA1E3BA155E74754DA6682D04747 | #| 127.% | msandbox_rw | *6C387FC3893DBA1E3BA155E74754DA6682D04747 | #| 127.% | msandbox_ro | *6C387FC3893DBA1E3BA155E74754DA6682D04747 | #| localhost | msandbox_ro | *6C387FC3893DBA1E3BA155E74754DA6682D04747 | #| 127.% | rsandbox | *B07EB15A2E7BD9620DAE47B194D5B9DBA14377AD | #+-----------+-------------+-------------------------------------------+ sql: path = $SANDBOX_HOME/msb_XXXX/ query = select count(*) from mysql.user expected = 8 msg = number of users sql: path = $SANDBOX_HOME/msb_XXXX/ query = select count(*) from mysql.user where host = '127.%' expected = 4 msg = number of users with host '127.%' sql: path = $SANDBOX_HOME/msb_XXXX/ query = select count(*) from mysql.user where user = 'msandbox' expected = 2 msg = number of 'msandbox' users sql: path = $SANDBOX_HOME/msb_XXXX/ query = select count(*) from mysql.user where password = password('msandbox') expected = 7 msg = number of 'msandbox' passwords sql: path = $SANDBOX_HOME/msb_XXXX/ query = select user from mysql.user where password = password('rsandbox') expected = rsandbox msg = user with 'rsandbox' password shell: command = $SANDBOX_HOME/msb_XXXX/use -u msandbox_rw -e 'create table test.t1( i int)' expected = ok msg = table creation allowed shell: command = $SANDBOX_HOME/msb_XXXX/use -u msandbox_rw -e 'insert into test.t1 values (2011)' expected = ok msg = table insertion allowed shell: command = $SANDBOX_HOME/msb_XXXX/use -u msandbox_ro -e 'create table test.t2(i int)' 2>&1 || echo 1 expected = denied msg = table creation denied shell: command = $SANDBOX_HOME/msb_XXXX/use -u msandbox_ro -e 'select * from test.t1' expected = 2011 msg = table selection allowed shell: command = $SANDBOX_HOME/msb_XXXX/use -u msandbox_rw -e 'drop table test.t1' expected = ok msg = table drop allowed shell: command = $SANDBOX_HOME/msb_XXXX/use -h 127.0.0.1 -u rsandbox -prsandbox -e 'show grants for rsandbox@"127.%"' expected = REPLICATION SLAVE msg = replication slave user ########################################### # checking user privileges in replication ########################################### shell: command = make_replication_sandbox --replication_directory=rsandbox_XXXX $TEST_VERSION expected = replication directory installed msg = replication started sql: path = $SANDBOX_HOME/rsandbox_XXXX/node1/ query = select sleep(1) expected = 0 msg = pause, waiting for replication sql: path = $SANDBOX_HOME/rsandbox_XXXX/master/ query = select count(*) from mysql.user expected = 8 msg = number of users (master) sql: path = $SANDBOX_HOME/rsandbox_XXXX/master/ query = select count(*) from mysql.user where host = '127.%' expected = 4 msg = number of users with host '127.%' (master) sql: path = $SANDBOX_HOME/rsandbox_XXXX/master/ query = select count(*) from mysql.user where user = 'msandbox' expected = 2 msg = number of 'msandbox' users (master) sql: path = $SANDBOX_HOME/rsandbox_XXXX/master/ query = select count(*) from mysql.user where password = password('msandbox') expected = 7 msg = number of 'msandbox' passwords (master) sql: path = $SANDBOX_HOME/rsandbox_XXXX/master/ query = select user from mysql.user where password = password('rsandbox') expected = rsandbox msg = user with 'rsandbox' password (master) shell: command = $SANDBOX_HOME/rsandbox_XXXX/master/use -u msandbox_rw -e 'create table test.t1( i int)' expected = ok msg = table creation allowed (master) shell: command = $SANDBOX_HOME/rsandbox_XXXX/master/use -u msandbox_rw -e 'insert into test.t1 values (2011)' expected = ok msg = table insertion allowed (master) shell: command = $SANDBOX_HOME/rsandbox_XXXX/master/use -u msandbox_ro -e 'create table test.t2(i int)' 2>&1 || echo 1 expected = denied msg = table creation denied (master) shell: command = $SANDBOX_HOME/rsandbox_XXXX/master/use -u msandbox_ro -e 'select * from test.t1' expected = 2011 msg = table selection allowed (master) shell: command = $SANDBOX_HOME/rsandbox_XXXX/master/use -u msandbox_rw -e 'drop table test.t1' expected = ok msg = table drop allowed (master) shell: command = $SANDBOX_HOME/rsandbox_XXXX/master/use -h 127.0.0.1 -u rsandbox -prsandbox -e 'show grants for rsandbox@"127.%"' expected = REPLICATION SLAVE msg = replication slave user (master) sql: path = $SANDBOX_HOME/rsandbox_XXXX/node1/ query = select count(*) from mysql.user expected = 8 msg = number of users (node1) sql: path = $SANDBOX_HOME/rsandbox_XXXX/node1/ query = select count(*) from mysql.user where host = '127.%' expected = 4 msg = number of users with host '127.%' (node1) sql: path = $SANDBOX_HOME/rsandbox_XXXX/node1/ query = select count(*) from mysql.user where user = 'msandbox' expected = 2 msg = number of 'msandbox' users (node1) sql: path = $SANDBOX_HOME/rsandbox_XXXX/node1/ query = select count(*) from mysql.user where password = password('msandbox') expected = 7 msg = number of 'msandbox' passwords (node1) sql: path = $SANDBOX_HOME/rsandbox_XXXX/node1/ query = select user from mysql.user where password = password('rsandbox') expected = rsandbox msg = user with 'rsandbox' password (node1) shell: command = $SANDBOX_HOME/rsandbox_XXXX/node1/use -u msandbox_rw -e 'create table test.t11( i int)' expected = ok msg = table creation allowed (node1) shell: command = $SANDBOX_HOME/rsandbox_XXXX/node1/use -u msandbox_rw -e 'insert into test.t11 values (2011)' expected = ok msg = table insertion allowed (node1) shell: command = $SANDBOX_HOME/rsandbox_XXXX/node1/use -u msandbox_ro -e 'create table test.t2(i int)' 2>&1 || echo 1 expected = denied msg = table creation denied (node1) shell: command = $SANDBOX_HOME/rsandbox_XXXX/node1/use -u msandbox_ro -e 'select * from test.t11' expected = 2011 msg = table selection allowed (node1) shell: command = $SANDBOX_HOME/rsandbox_XXXX/node1/use -u msandbox_rw -e 'drop table test.t11' expected = ok msg = table drop allowed (node1) shell: command = $SANDBOX_HOME/rsandbox_XXXX/node1/use -h 127.0.0.1 -u rsandbox -prsandbox -e 'show grants for rsandbox@"127.%"' expected = REPLICATION SLAVE msg = replication slave user (node1) shell: command = sbtool -o delete -s $SANDBOX_HOME/msb_XXXX expected = ok msg = single sandbox removed shell: command = sbtool -o delete -s $SANDBOX_HOME/rsandbox_XXXX expected = ok msg = replication sandbox removed ################################################# # checking remote access ('%' instead of '127.%') ################################################# shell: command = make_sandbox $TEST_VERSION -- --no_confirm --sandbox_directory=msb_XXXX --remote_access=% expected = sandbox server started msg = sandbox creation sql: path = $SANDBOX_HOME/msb_XXXX/ query = select count(*) from mysql.user expected = 8 msg = number of users sql: path = $SANDBOX_HOME/msb_XXXX/ query = select count(*) from mysql.user where host = '127.%' expected = 0 msg = number of users with host '127.%' sql: path = $SANDBOX_HOME/msb_XXXX/ query = select count(*) from mysql.user where host = '%' expected = 4 msg = number of users with host '%' shell: command = make_replication_sandbox --replication_directory=rsandbox_XXXX --remote_access=% $TEST_VERSION expected = replication directory installed msg = replication started sql: path = $SANDBOX_HOME/rsandbox_XXXX/node1/ query = select count(*) from mysql.user expected = 8 msg = number of users (node1) sql: path = $SANDBOX_HOME/rsandbox_XXXX/node1/ query = select count(*) from mysql.user where host = '127.%' expected = 0 msg = number of users with host '127.%' (node1) sql: path = $SANDBOX_HOME/rsandbox_XXXX/node1/ query = select count(*) from mysql.user where host = '%' expected = 4 msg = number of users with host '%' (node1) sql: path = $SANDBOX_HOME/rsandbox_XXXX/master/ query = select count(*) from mysql.user expected = 8 msg = number of users (master) sql: path = $SANDBOX_HOME/rsandbox_XXXX/master/ query = select count(*) from mysql.user where host = '127.%' expected = 0 msg = number of users with host '127.%' (master) sql: path = $SANDBOX_HOME/rsandbox_XXXX/master/ query = select count(*) from mysql.user where host = '%' expected = 4 msg = number of users with host '%' (master) shell: command = $SANDBOX_HOME/msb_XXXX/stop expected = OK msg = stopped shell: command = $SANDBOX_HOME/rsandbox_XXXX/stop_all expected = OK msg = replication stopped MySQL-Sandbox-3.1.04/t/user_privileges.sb.pl000644 000765 000024 00000026210 12624042333 020651 0ustar00gmaxstaff000000 000000 ########################################### # checking default user privileges ########################################### # my $TEST_VERSION = $ENV{TEST_VERSION}; my ($bare_version, $version, $major, $minor, $rev) = get_bare_version ($TEST_VERSION); my $SANDBOX_HOME= $ENV{SANDBOX_HOME} || "$ENV{HOME}/sandboxes"; my $password_field='password'; my $number_of_users = 8; if ( (($major ==5) && ($minor > 7) ) or ( ($major ==5) && ($minor == 7) && ($rev > 5) ) ) # Starting with MySQL 5.7.6, the 'password' column in the user table is gone # There is , instead, a column named 'authentication_string' { $password_field='authentication_string'; } if ( (($major ==5) && ($minor > 7) ) or ( ($major ==5) && ($minor == 7) && ($rev > 8) ) ) # Starting with MySQL 5.7.9 we have the mysql.sys user created by default. { $number_of_users = 9; } ok_exec({ command => "make_sandbox $TEST_VERSION -- --no_confirm --sandbox_directory=msb_XXXX", expected => "sandbox server started", msg => "sandbox creation", }); #+-----------+-------------+-------------------------------------------+ #| host | user | password | #+-----------+-------------+-------------------------------------------+ #| localhost | root | *6C387FC3893DBA1E3BA155E74754DA6682D04747 | #| 127.% | msandbox | *6C387FC3893DBA1E3BA155E74754DA6682D04747 | #| localhost | msandbox | *6C387FC3893DBA1E3BA155E74754DA6682D04747 | #| localhost | msandbox_rw | *6C387FC3893DBA1E3BA155E74754DA6682D04747 | #| 127.% | msandbox_rw | *6C387FC3893DBA1E3BA155E74754DA6682D04747 | #| 127.% | msandbox_ro | *6C387FC3893DBA1E3BA155E74754DA6682D04747 | #| localhost | msandbox_ro | *6C387FC3893DBA1E3BA155E74754DA6682D04747 | #| 127.% | rsandbox | *B07EB15A2E7BD9620DAE47B194D5B9DBA14377AD | #+-----------+-------------+-------------------------------------------+ ok_sql({ path => "$SANDBOX_HOME/msb_XXXX/", query => "select count(*) from mysql.user", expected => "$number_of_users", msg => "number of users", }); ok_sql({ path => "$SANDBOX_HOME/msb_XXXX/", query => "select count(*) from mysql.user where host = '127.%'", expected => "4", msg => "number of users with host '127.%'", }); ok_sql({ path => "$SANDBOX_HOME/msb_XXXX/", query => "select count(*) from mysql.user where user = 'msandbox'", expected => "2", msg => "number of 'msandbox' users", }); ok_sql({ path => "$SANDBOX_HOME/msb_XXXX/", query => "select count(*) from mysql.user where $password_field = password('msandbox')", expected => "7", msg => "number of 'msandbox' passwords", }); ok_sql({ path => "$SANDBOX_HOME/msb_XXXX/", query => "select user from mysql.user where $password_field = password('rsandbox')", expected => "rsandbox", msg => "user with 'rsandbox' password", }); ok_exec({ command => "$SANDBOX_HOME/msb_XXXX/use -u msandbox_rw -e 'create table test.t1( i int)'", expected => "ok", msg => "table creation allowed", }); ok_exec({ command => "$SANDBOX_HOME/msb_XXXX/use -u msandbox_rw -e 'insert into test.t1 values (2011)'", expected => "ok", msg => "table insertion allowed", }); ok_exec({ command => "$SANDBOX_HOME/msb_XXXX/use -u msandbox_ro -e 'create table test.t2(i int)' 2>&1 || echo 1", expected => "denied", msg => "table creation denied", }); ok_exec({ command => "$SANDBOX_HOME/msb_XXXX/use -u msandbox_ro -e 'select * from test.t1'", expected => "2011", msg => "table selection allowed", }); ok_exec({ command => "$SANDBOX_HOME/msb_XXXX/use -u msandbox_rw -e 'drop table test.t1'", expected => "ok", msg => "table drop allowed", }); ok_exec({ command => qq($SANDBOX_HOME/msb_XXXX/use -h 127.0.0.1 -u rsandbox -prsandbox -e 'show grants for rsandbox@"127.%"'), expected => "REPLICATION SLAVE", msg => "replication slave user", }); ########################################### # checking user privileges in replication ########################################### ok_exec({ command => "make_replication_sandbox --replication_directory=rsandbox_XXXX $TEST_VERSION ", expected => "replication directory installed", msg => "replication started", }); sleep 1; ok_sql({ path => "$SANDBOX_HOME/rsandbox_XXXX/master/", query => "select count(*) from mysql.user", expected => "$number_of_users", msg => "number of users (master)", }); ok_sql({ path => "$SANDBOX_HOME/rsandbox_XXXX/master/", query => "select count(*) from mysql.user where host = '127.%'", expected => "4", msg => "number of users with host '127.%' (master)", }); ok_sql({ path => "$SANDBOX_HOME/rsandbox_XXXX/master/", query => "select count(*) from mysql.user where user = 'msandbox'", expected => "2", msg => "number of 'msandbox' users (master)", }); ok_sql({ path => "$SANDBOX_HOME/rsandbox_XXXX/master/", query => "select count(*) from mysql.user where $password_field = password('msandbox')", expected => "7", msg => "number of 'msandbox' passwords (master)", }); ok_sql({ path => "$SANDBOX_HOME/rsandbox_XXXX/master/", query => "select user from mysql.user where $password_field = password('rsandbox')", expected => "rsandbox", msg => "user with 'rsandbox' password (master)", }); ok_exec({ command => "$SANDBOX_HOME/rsandbox_XXXX/master/use -u msandbox_rw -e 'create table test.t1( i int)'", expected => "ok", msg => "table creation allowed (master)", }); ok_exec({ command => "$SANDBOX_HOME/rsandbox_XXXX/master/use -u msandbox_rw -e 'insert into test.t1 values (2011)'", expected => "ok", msg => "table insertion allowed (master)", }); ok_exec({ command => "$SANDBOX_HOME/rsandbox_XXXX/master/use -u msandbox_ro -e 'create table test.t2(i int)' 2>&1 || echo 1", expected => "denied", msg => "table creation denied (master)", }); ok_exec({ command => "$SANDBOX_HOME/rsandbox_XXXX/master/use -u msandbox_ro -e 'select * from test.t1'", expected => "2011", msg => "table selection allowed (master)", }); ok_exec({ command => "$SANDBOX_HOME/rsandbox_XXXX/master/use -u msandbox_rw -e 'drop table test.t1'", expected => "ok", msg => "table drop allowed (master)", }); ok_exec({ command => qq($SANDBOX_HOME/rsandbox_XXXX/master/use -h 127.0.0.1 -u rsandbox -prsandbox -e 'show grants for rsandbox@"127.%"'), expected => "REPLICATION SLAVE", msg => "replication slave user (master)", }); ok_sql({ path => "$SANDBOX_HOME/rsandbox_XXXX/node1/", query => "select count(*) from mysql.user", expected => "$number_of_users", msg => "number of users (node1)", }); ok_sql({ path => "$SANDBOX_HOME/rsandbox_XXXX/node1/", query => "select count(*) from mysql.user where host = '127.%'", expected => "4", msg => "number of users with host '127.%' (node1)", }); ok_sql({ path => "$SANDBOX_HOME/rsandbox_XXXX/node1/", query => "select count(*) from mysql.user where user = 'msandbox'", expected => "2", msg => "number of 'msandbox' users (node1)", }); ok_sql({ path => "$SANDBOX_HOME/rsandbox_XXXX/node1/", query => "select count(*) from mysql.user where $password_field = password('msandbox')", expected => "7", msg => "number of 'msandbox' passwords (node1)", }); ok_sql({ path => "$SANDBOX_HOME/rsandbox_XXXX/node1/", query => "select user from mysql.user where $password_field = password('rsandbox')", expected => "rsandbox", msg => "user with 'rsandbox' password (node1)", }); ok_exec({ command => "$SANDBOX_HOME/rsandbox_XXXX/node1/use -u msandbox_rw -e 'create table test.t11( i int)'", expected => "ok", msg => "table creation allowed (node1)", }); ok_exec({ command => "$SANDBOX_HOME/rsandbox_XXXX/node1/use -u msandbox_rw -e 'insert into test.t11 values (2011)'", expected => "ok", msg => "table insertion allowed (node1)", }); ok_exec({ command => "$SANDBOX_HOME/rsandbox_XXXX/node1/use -u msandbox_ro -e 'create table test.t2(i int)' 2>&1 || echo 1", expected => "denied", msg => "table creation denied (node1)", }); ok_exec({ command => "$SANDBOX_HOME/rsandbox_XXXX/node1/use -u msandbox_ro -e 'select * from test.t11'", expected => "2011", msg => "table selection allowed (node1)", }); ok_exec({ command => "$SANDBOX_HOME/rsandbox_XXXX/node1/use -u msandbox_rw -e 'drop table test.t11'", expected => "ok", msg => "table drop allowed (node1)", }); ok_exec({ command => qq($SANDBOX_HOME/rsandbox_XXXX/node1/use -h 127.0.0.1 -u rsandbox -prsandbox -e 'show grants for rsandbox@"127.%"'), expected => "REPLICATION SLAVE", msg => "replication slave user (node1)", }); ok_exec({ command => "sbtool -o delete -s $SANDBOX_HOME/msb_XXXX", expected => "ok", msg => "single sandbox removed", }); ok_exec({ command => "sbtool -o delete -s $SANDBOX_HOME/rsandbox_XXXX", expected => "ok", msg => "replication sandbox removed", }); ################################################# # checking remote access ('%' instead of '127.%') ################################################# ok_exec({ command => "make_sandbox $TEST_VERSION -- --no_confirm --sandbox_directory=msb_XXXX --remote_access=%", expected => "sandbox server started", msg => "sandbox creation", }); ok_sql({ path => "$SANDBOX_HOME/msb_XXXX/", query => "select count(*) from mysql.user", expected => "$number_of_users", msg => "number of users", }); ok_sql({ path => "$SANDBOX_HOME/msb_XXXX/", query => "select count(*) from mysql.user where host = '127.%'", expected => "0", msg => "number of users with host '127.%'", }); ok_sql({ path => "$SANDBOX_HOME/msb_XXXX/", query => "select count(*) from mysql.user where host = '%'", expected => "4", msg => "number of users with host '%'", }); ok_exec({ command => "make_replication_sandbox --replication_directory=rsandbox_XXXX --remote_access=% $TEST_VERSION ", expected => "replication directory installed", msg => "replication started", }); ok_sql({ path => "$SANDBOX_HOME/rsandbox_XXXX/node1/", query => "select count(*) from mysql.user", expected => "$number_of_users", msg => "number of users (node1)", }); ok_sql({ path => "$SANDBOX_HOME/rsandbox_XXXX/node1/", query => "select count(*) from mysql.user where host = '127.%'", expected => "0", msg => "number of users with host '127.%' (node1)", }); ok_sql({ path => "$SANDBOX_HOME/rsandbox_XXXX/node1/", query => "select count(*) from mysql.user where host = '%'", expected => "4", msg => "number of users with host '%' (node1)", }); ok_sql({ path => "$SANDBOX_HOME/rsandbox_XXXX/master/", query => "select count(*) from mysql.user", expected => "$number_of_users", msg => "number of users (master)", }); ok_sql({ path => "$SANDBOX_HOME/rsandbox_XXXX/master/", query => "select count(*) from mysql.user where host = '127.%'", expected => "0", msg => "number of users with host '127.%' (master)", }); ok_sql({ path => "$SANDBOX_HOME/rsandbox_XXXX/master/", query => "select count(*) from mysql.user where host = '%'", expected => "4", msg => "number of users with host '%' (master)", }); ok_exec({ command => "$SANDBOX_HOME/msb_XXXX/stop", expected => "OK", msg => "stopped ", }); ok_exec({ command => "$SANDBOX_HOME/rsandbox_XXXX/stop_all", expected => "OK", msg => "replication stopped", }); MySQL-Sandbox-3.1.04/lib/MySQL/000755 000765 000024 00000000000 12631550766 015765 5ustar00gmaxstaff000000 000000 MySQL-Sandbox-3.1.04/lib/MySQL/Sandbox/000755 000765 000024 00000000000 12631550766 017363 5ustar00gmaxstaff000000 000000 MySQL-Sandbox-3.1.04/lib/MySQL/Sandbox.pm000644 000765 000024 00000146102 12631423373 017716 0ustar00gmaxstaff000000 000000 package MySQL::Sandbox; use strict; use warnings; use Carp; use English qw( -no_match_vars ); use Socket; use File::Find; use Data::Dumper; use base qw( Exporter); our @ISA= qw(Exporter); our @EXPORT_OK= qw( is_port_open runs_as_root exists_in_path is_a_sandbox find_safe_port_and_directory first_unused_port get_sandbox_params is_sandbox_running get_sb_info get_ports get_ranges use_env sbinstr get_json_from_dirs get_option_file_contents validate_json_object fix_server_uuid greater_version split_version ) ; our $VERSION="3.1.04"; our $DEBUG; BEGIN { $DEBUG = $ENV{'SBDEBUG'} || $ENV{'SBVERBOSE'} || 0; unless ($ENV{HOME}) { die "This module is not meant for an operating system\n" . "that does not recognize \$HOME\n"; } unless ( $ENV{SANDBOX_HOME} ) { $ENV{SANDBOX_HOME} = "$ENV{HOME}/sandboxes"; } unless ($ENV{TMPDIR}) { $ENV{TMPDIR} = '/tmp'; } unless ( -d $ENV{TMPDIR}) { die "could not find $ENV{TMPDIR}\n"; } if ( -d "$ENV{HOME}/sandboxes" ) { $ENV{SANDBOX_HOME} = $ENV{SANDBOX_HOME} || "$ENV{HOME}/sandboxes"; } unless ( $ENV{SANDBOX_BINARY} ) { if ( -d "$ENV{HOME}/opt/mysql") { $ENV{SANDBOX_BINARY} = "$ENV{HOME}/opt/mysql"; } else { $ENV{SANDBOX_BINARY} = ''; } } } my @supported_versions = qw( 3.23 4.0 4.1 5.0 5.1 5.2 5.3 5.4 5.5 5.6 5.7 5.8 6.0 10.0 10.1 ); our $sandbox_options_file = "my.sandbox.cnf"; # our $sandbox_current_options = "current_options.conf"; our %default_base_port = ( replication => 11000, circular => 14000, multiple => 7000, custom => 5000, ); our %default_users = ( db_user => 'msandbox', remote_access => '127.%', db_password => 'msandbox', ro_user => 'msandbox_ro', rw_user => 'msandbox_rw', repl_user => 'rsandbox', repl_password => 'rsandbox', ); our $SBINSTR_SH_TEXT =<<'SBINSTR_SH_TEXT'; if [ -f "$SBINSTR" ] then echo "[`basename $0`] - `date "+%Y-%m-%d %H:%M:%S"` - $@" >> $SBINSTR fi SBINSTR_SH_TEXT sub new { my ($class) = @_; my $self = bless { parse_options => undef, options => undef, }, $class; # my $version = get_version( $install_dir); # $self->{version} = $VERSION; return $self; } sub parse_options { my ($self, $opt ) = @_; # print "<", ref($opt) , ">\n"; unless (ref($opt) eq 'HASH') { confess "parse_options must be a hash reference\n"; } if ($opt) { $self->{parse_options} = $opt; } my %options = map { $_ , $opt->{$_}{'value'}} keys %{$opt}; $self->{options} = \%options; return $self->{options}; } sub find_safe_port_and_directory { my ($wanted_port, $wanted_dir, $upper_directory) = @_; my $chosen_port = $wanted_port; my ($ports, undef) = get_sb_info( $ENV{SANDBOX_HOME}, undef); # print Dumper($ports); while ( is_port_open($chosen_port) or exists $ports->{$chosen_port}) { $chosen_port++; $chosen_port = first_unused_port($chosen_port); # print "checking -> $chosen_port\n"; } my $suffix = 'a'; my $chosen_dir = $wanted_dir; while ( -d "$upper_directory/$chosen_dir" ) { # print "checking -> $chosen_dir\n"; $chosen_dir = $wanted_dir . '_' . $suffix; $suffix++; } return ($chosen_port, $chosen_dir); } sub get_help { my ($self, $msg) = @_; if ($msg) { warn "[***] $msg\n\n"; } my $HELP_MSG = q{}; for my $op ( sort { $self->{parse_options}->{$a}{so} <=> $self->{parse_options}->{$b}{so} } grep { $self->{parse_options}->{$_}{parse}} keys %{ $self->{parse_options} } ) { my $param = $self->{parse_options}->{$op}{parse}; my $param_str = q{ }; my ($short, $long ) = $param =~ / (?: (\w) \| )? (\S+) /x; if ($short) { $param_str .= q{-} . $short . q{ }; } $long =~ s/ = s \@? / = name/x; $long =~ s/ = i / = number/x; $param_str .= q{--} . $long; $param_str .= (q{ } x (40 - length($param_str)) ); my $text_items = $self->{parse_options}->{$op}{help}; for my $titem (@{$text_items}) { $HELP_MSG .= $param_str . $titem . "\n"; $param_str = q{ } x 40; } if (@{$text_items} > 1) { $HELP_MSG .= "\n"; } # $HELP_MSG .= "\n"; } my $VAR_HELP = "\nVARIABLES affecting this program: \n" . "\t\$SBDEBUG : DEBUG LEVEL (" . ($ENV{SBDEBUG} || 0) . ")\n" . "\t\$SBVERBOSE : DEBUG LEVEL (same as \$SBDEBUG) (" . ($ENV{SBVERBOSE} || 0) . ")\n" . "\t\$SANDBOX_HOME : root of all sandbox installations (" . use_env($ENV{SANDBOX_HOME}) . ")\n" . "\t\$SANDBOX_BINARY : where to search for binaries (" . use_env($ENV{SANDBOX_BINARY}) . ")\n" ; if ( $PROGRAM_NAME =~ /replication|multiple/ ) { $VAR_HELP .= "\t\$NODE_OPTIONS : options to pass to all node installations (" . ($ENV{NODE_OPTIONS} || '') . ")\n" } if ( $PROGRAM_NAME =~ /replication/ ) { $VAR_HELP .= "\t\$MASTER_OPTIONS : options to pass to the master installation (" . ($ENV{MASTER_OPTIONS} || '') . ")\n" . "\t\$SLAVE_OPTIONS : options to pass to all slave installations (" . ($ENV{SLAVE_OPTIONS} || '' ) . ")\n" } my $target = ''; if ( grep {$PROGRAM_NAME =~ /$_/ } qw( make_sandbox make_replication_sandbox make_multiple_sandbox make_multiple_sandbox ) ) { $target = '{tarball|dir|version}'; $HELP_MSG = "tarball = the full path to a MySQL binary tarball\n" . "dir = the path to an expanded MySQL binary tarball\n" . "version = the simple version number of the expanded tarball\n" . " if it is under \$SANDBOX_BINARY and renamed as the\n " . " version number.\n\n" . $HELP_MSG; } print $self->credits(), "syntax: $PROGRAM_NAME [options] $target \n", $HELP_MSG, $VAR_HELP; # This example is only relevant for a single sandbox, but it is # wrong for a multiple sandbox. #, #"\nExample:\n", #" $PROGRAM_NAME --my_file=large --sandbox_directory=my_sandbox\n\n"; exit(1); } sub credits { my ($self) = @_; my $CREDITS = qq( The MySQL Sandbox, version $VERSION\n) . qq( (C) 2006-2015 Giuseppe Maxia\n); return $CREDITS; } sub split_version { my ($v) = @_; if ($v =~ /(\d+)\.(\d+)\.(\d+)/ ) { return ($1, $2, $3) } else { die "# Split version: could not get components from <$v>\n"; } } sub greater_version { my ($v1, $v2) = @_; my ($v1_major, $v1_minor, $v1_rev) = split_version($v1); my ($v2_major, $v2_minor, $v2_rev) = split_version($v2); if ( $v1_major > $v2_major) { return 1; } elsif ( ($v1_major == $v2_major) && ($v1_minor > $v2_minor)) { return 1; } elsif ( ($v1_major == $v2_major) && ($v1_minor == $v2_minor) && ($v1_rev > $v2_rev) ) { return 1; } return 0 } sub fix_server_uuid { my ($server_id, $version, $port, $sandbox_directory) = @_; if ($version =~ /(\d+)\.(\d+)/) { my ($major, $minor ) = ($1, $2); unless (($major == 5) && ($minor >=6)) { return; } } my $current_dir = $ENV{PWD}; my $increase_id = 0; $sandbox_directory =~ s{/$}{}; my $operation_dir= "$sandbox_directory/data"; if ( ! -d $operation_dir) { die "<$operation_dir> not found\n"; } chdir $operation_dir; print "# operation_dir is $operation_dir\n" if $DEBUG; if ( ($operation_dir =~ m{/node\d/data$}) && (-d "../../master")) { $increase_id =1; } # 12345678 1234 1234 1234 123456789012 # my $new_uuid='00000000-0000-0000-0000-000000000000'; my $group1 = sprintf('%08d', $port); my $group2= sprintf('%04d-%04d-%04d-%012d', 0,0,0,0); if ($server_id < 10) { $group2 =~ s/\d/$server_id/g; } elsif (($server_id >= 100) && ($server_id < 109)) { $server_id -= 100; $server_id += 1 if $increase_id; # 101 => 2 $group2 =~ s/\d/$server_id/g; } else { my $second_id = $server_id; if ($second_id > 9999) { $second_id = 9999; } $group2 = sprintf( '%04d-%04d-%04d-%012d', $second_id, $second_id, $second_id, $server_id ); } my $new_uuid= "$group1-$group2"; open my $FH, '>', 'auto.cnf' or die "Error updating 'auto.cnf' ($!)\n"; print $FH "[auto]\n"; print $FH "server-uuid=$new_uuid\n"; close $FH; chdir $current_dir; } sub validate_json_object { my ($json_filename, $json_text) = @_; my $JSON_module = undef; for my $module ( 'JSON', 'JSON::PP', 'JSON::XS') { eval "use $module;"; if (! $@) { print "# Using $module\n" if $DEBUG; $JSON_module=$module; last; } } unless ($JSON_module) { print "# JSON modules not installed - skipped evaluation\n" if $DEBUG; return -1; } unless ($json_text) { $json_text = slurp($json_filename); } my $json = $JSON_module->new->allow_nonref; my $perl_value; eval { $perl_value = $json->decode( $json_text ); }; if ($@) { print "error decoding json object\n" if $DEBUG; return ; } return 1; } sub slurp { my ($filename, $skip_blanks, $skip_comments ) = @_; open my $FH , q{<}, $filename or die "file '$filename' not found\n"; my @text_array = (); my $text=''; while (my $line = <$FH>) { if ($skip_blanks) { next if $line =~ /^\s*$/; } if ($skip_comments) { next if $line =~ /^\s*#/; } if (wantarray) { push @text_array, $line; } else { $text .= $line; } } close $FH; if (wantarray) { return @text_array; } else { return $text; } } sub get_json_from_dirs { my ($directories, $json_file) = @_; my $collective_json = ''; my $indent = ' '; for my $dir (@$directories) { my $filename = "$dir/$json_file"; if ($collective_json) { $collective_json .= ",\n" } else { $collective_json = "{\n"; } $collective_json .= qq("$dir": \n); if ( -f $filename) { # get the contents my @json_lines = slurp($filename, 'skip_blanks'); for my $jl (@json_lines) { $collective_json .= $indent . $jl; } } else { if ($DEBUG) { warn "# No connection.json found in $dir\n"; my ($package, $filename, $line) = caller; warn "# called from $package - $filename - $line \n"; } $collective_json .= "{}"; } } $collective_json .= "}"; my $is_valid_json = validate_json_object(undef, $collective_json); if ($is_valid_json && ($is_valid_json == -1)) { if ($DEBUG) { warn "# Could not validate JSON object\n"; } } elsif ( ! $is_valid_json) { warn "Invalid JSON object in $ENV{PWD} from [@$directories] \n"; $collective_json = qq({ "comment": "WARNING: invalid JSON object", "original" : ) . $collective_json . "\n}"; } return $collective_json; } #sub get_version { # my ($install_dir) = @_; # open my $VER , q{<}, "$install_dir/VERSION" # #open my $VER , q{<}, "VERSION" # or die "file 'VERSION' not found\n"; # my $version = <$VER>; # chomp $version; # close $VER; # return $version; #} sub write_to { my ($self, $fname, $mode, $contents) = @_; open my $FILE, $mode, $fname or die "can't open file $fname\n"; print $FILE $contents, "\n"; if (($mode eq '>') && ( $contents =~ m/\#!\/bin\/sh/ ) ) { print $FILE $SBINSTR_SH_TEXT; } close $FILE; } sub supported_versions { return \@supported_versions; } sub is_port_open { my ($port) = @_; die "No port" unless $port; my ($host, $iaddr, $paddr, $proto); $host = '127.0.0.1'; $iaddr = inet_aton($host) or die "no host: $host"; $paddr = sockaddr_in($port, $iaddr); $proto = getprotobyname('tcp'); socket(SOCK, PF_INET, SOCK_STREAM, $proto) or die "error creating test socket for port $port: $!"; if (connect(SOCK, $paddr)) { close (SOCK) or die "error closing test socket: $!"; return 1; } return 0; } sub first_unused_port { my ($port) = @_; while (is_port_open($port)) { $port++; if ($port > 0xFFF0) { die "no ports available\n"; } } return $port; } ## # SBtool # sub get_sandbox_params { my ($dir, $skip_strict) = @_; confess "directory name required\n" unless $dir; confess "directory $dir doesn't exist\n" unless -d $dir; unless (is_a_sandbox($dir)) { confess "directory <$dir> must be a sandbox\n" unless $skip_strict; } my %params = ( opt => undef, conf => undef ); if ( -f "$dir/$sandbox_options_file" ) { $params{opt} = get_option_file_contents("$dir/$sandbox_options_file"); } else { # warn "options file $dir not found\n"; return; } # if ( -f "$dir/$sandbox_current_options" ) { # $params{conf} = # get_option_file_contents("$dir/$sandbox_current_options"); # } # else { # # warn "current conf file not found\n"; # return; # } return \%params; } sub get_option_file_contents { my ($file) = @_; confess "file name required\n" unless $file; confess "file $file doesn't exist\n" unless -f $file; my %options; open my $RFILE, q{<}, $file or confess "can't open file $file\n"; while ( my $line = <$RFILE> ) { next if $line =~ /^\s*$/; next if $line =~ /^\s*#/; next if $line =~ /^\s*\[/; chomp $line; my ( $key, $val ) = split /\s*=\s*/, $line; $key =~ s/-/_/g; $options{$key} = $val; } close $RFILE; # print Dumper(\%options) ; exit; return \%options; } sub get_sb_info { my ($search_path, $options) = @_; my %ports = (); my %all_info = (); my $seen_dir = ''; find( { no_chdir => 1, follow => 1, wanted => sub { if ( $seen_dir eq $File::Find::dir ) { return; } my $params; if ( $params = get_sandbox_params($File::Find::dir, 1) ) { $seen_dir = $File::Find::dir; my $port = $params->{opt}{port}; if ( -f $params->{opt}{pid_file} && -e $params->{opt}{socket} ) { $ports{$port} = 1; $all_info{$port} = $params if $options->{all_info}; } else { unless ( $options->{only_used} ) { $ports{$port} = 0; $all_info{$port} = $params if $options->{all_info}; } } } } }, $search_path || $options->{search_path} ); return ( \%ports, \%all_info ); } sub is_a_sandbox { my ($dir) = @_; unless ($dir) { confess "directory missing\n"; } $dir =~ s{/$}{}; my %sandbox_files = map {s{.*/}{}; $_, 1 } glob("$dir/*"); my @required = (qw(data start stop send_kill clear use restart), # $sandbox_current_options, $sandbox_options_file ); for my $req (@required) { unless (exists $sandbox_files{$req}) { return; } } return 1; } sub is_sandbox_running { my ($sandbox) = @_; unless ( -d $sandbox ) { confess "Can't see if it's running. <$sandbox> is not a sandbox\n"; } my $sboptions = get_sandbox_params($sandbox); unless ($sboptions->{opt} && $sboptions->{opt}{'pid_file'} && $sboptions->{opt}{'socket'}) { # print Dumper($sboptions); confess "<$sandbox> is not a single sandbox\n"; } if ( ( -f $sboptions->{opt}{'pid_file'} ) && ( -e $sboptions->{opt}{'socket'}) ) { return (1, $sboptions); } else { return (0, $sboptions); } } sub get_ranges { my ($options, $silent ) = @_; my ( $ports, $all_info ) = get_sb_info(undef, $options); my $minimum_port = $options->{min_range}; my $maximum_port = $options->{max_range}; my $range_size = $options->{range_size}; if ( $minimum_port >= $maximum_port ) { croak "minimum range must be lower than the maximum range\n"; } if ( ( $minimum_port + $range_size ) > $maximum_port ) { croak "range too wide for given boundaries\n"; } my $range_found = 0; range_search: while ( !$range_found ) { if ( $minimum_port >= $maximum_port ) { croak "can't find a range of $range_size " . "free ports between " . "$options->{min_range} and $options->{max_range}\n"; } for my $i ( $minimum_port .. $minimum_port + $range_size ) { if ( exists $ports->{$i} or ( $i >= $maximum_port ) ) { $minimum_port = $i + 1; next range_search; } } $range_found = 1; } unless ($silent) { printf "%5d - %5d\n", $minimum_port , $minimum_port + $range_size; } return $minimum_port; } sub get_ports { my ($options) = @_; my ( $ports, $all_info ) = get_sb_info(undef, $options); if ( $options->{format} eq 'perl' ) { print Data::Dumper->Dump( [$ports], ['ports'] ); print Data::Dumper->Dump( [$all_info], ['all_info'] ) if $options->{all_info}; } elsif ( $options->{format} eq 'text' ) { for my $port ( sort { $a <=> $b } keys %$ports ) { printf "%5d %2d\n", $port, $ports->{$port}; } } else { croak "unrecognized format -> $options->{format}\n"; } return ( $ports, $all_info ); } sub exists_in_path { my ($cmd) = @_; my @path_directories = split /:/, $ENV{PATH}; ## no critic for my $dir (@path_directories) { if ( -x "$dir/$cmd") { return 1; } } return 0; } sub runs_as_root { if ( ($REAL_USER_ID == 0) or ($EFFECTIVE_USER_ID == 0)) { unless ($ENV{SANDBOX_AS_ROOT}) { die "MySQL Sandbox should not run as root\n" . "\n" . "If you know what you are doing and want to\n " . "run as root nonetheless, please set the environment\n" . "variable 'SANDBOX_AS_ROOT' to a nonzero value\n"; } } } # # Replaces a path portion with an environment variable name # if a match is found # sub use_env{ my ($path) = @_; my @vars = ( 'HOME', 'SANDBOX_HOME', ); return '' unless $path; for my $var (@vars) { if ($path =~ /^$ENV{$var}/) { $path =~ s/$ENV{$var}/\$$var/; return $path; } } return $path; } sub sbinstr { my ($msg) = @_; unless ($ENV{SBINSTR}) { return; } my $pname = $PROGRAM_NAME; unless ($DEBUG) { $pname =~ s{.*/}{}; } open my $FH, '>>', $ENV{SBINSTR} or die "can't write to $ENV{SBINSTR} ($!)\n"; my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(); $mon++; $year +=1900; print $FH "[$pname] - ", sprintf('%4d-%02d%02d %02d:%02d:%02d', $year, $mon, $mday, $hour, $min, $sec), " - $msg \n"; close $FH; } 1; __END__ =head1 NAME MySQL::Sandbox - Quickly installs one or more MySQL servers in the same host, either standalone or in groups =head1 SYNOPSIS make_sandbox /path/to/MySQL-VERSION.tar.gz export SANDBOX_BINARY=$HOME/opt/mysql make_sandbox --export_binaries /path/to/MySQL-VERSION.tar.gz make_sandbox $SANDBOX_BINARY/VERSION make_sandbox VERSION =head1 PURPOSE This package is a sandbox for testing features under any version of MySQL from 3.23 to 5.x (and MariaDB 10). It will install one node under your home directory, and it will provide some useful commands to start, use and stop this sandbox. With this package you can play with new MySQL releases without need of using other computers. The server installed in the sandbox use non-standard data directory, ports and sockets, so they won't interfere with existing MYSQL installations. =head1 INSTALLATION MySQL Sandbox installs as a normal Perl Module. Since its purpose is to install side servers in user space, you can install it as root (default) or as an unprivileged user. In this case, you need to set the PERL5LIB and PATH variables. # as root perl Makefile.PL make make test make install # as normal user export PATH=$HOME/usr/local/bin:$PATH export PERL5LIB=$HOME/usr/local/lib/perl5/site_perl/x.x.x perl Makefile.PL PREFIX=$HOME/usr/local make make test make install Notice that PERL5LIB could be different in various operating systems. If you opt for this installation method, you must adapt it to your operating system path and Perl version. See also under L for more options before running 'make test' =head1 MAKING SANDBOXES =head2 Single server sandbox The easiest way to make a sandbox is =over 3 =item 1 download the sandbox package and install it as instructed above =item 2 download a MySQL binary tarball =item 3 run this command $ make_sandbox /path/to/mysql-X.X.XX-osinfo.tar.gz =back That's all it takes to get started. The Sandbox will ask you for confirmation, and then it will tell you where it has installed your server. By default, the sandbox creates a new instance for you under $SANDBOX_HOME/msb_X_X_XX =head2 Making a replication sandbox It's as easy as making a single sandbox $ make_replication_sandbox /path/to/mysql-X.X.XX-osinfo.tar.gz This will create a new instance of one master and two slaves under $SANDBOX_HOME/rsandbox_X_X_XX =head2 Circular replication It requires an appropriate option when you start a replication sandbox $ make_replication_sandbox --circular=4 /path/to/mysql-X.X.XX-osinfo.tar.gz This will create a replication system with three servers connected by circular replication. A handy shortcut is C<--master_master>, which will create a circular replication system of exactly two members. =head2 Multiple sandboxes You can create a group of sandboxes without any replication among its members. If you need three servers of the same version, you can use $ make_multiple_sandbox /path/to/tarball If you need servers of different versions in the same group, you may like $ make_multiple_custom_sandbox /path/to/tarball1 path/to/tarball2 /path/to/tb3 Assuming that each tarball is from a different version, you will group three servers under one directory, with the handy sandbox scripts to manipulate them. =head2 Creating a sandbox from source If you want to create a sandbox from the code that you have just compiled, but you don't want to install, there is a script that makesa binary tarball for you and installs a sandbox in one go. $ make_sandbox_from_source {SOURCE_DIRECTORY} {sandbox_type} [options] The first parameters is the directory where you have successfully run "./configure && make". The second parameter is what kind of sandbox you want to create: One of the following: * single * multiple * replication * circular You can then add all the options you need at the end. For example: $ make_sandbox_from_source $HOME/build/5.0 single --export_binaries --check_port or $ make_sandbox_from_source $HOME/build/5.0 replication --how_many_slaves=5 If you call this program several times from the same directory, it will check if the compiled binaries are newer than the extracted ones, and if they aren't, it will reuse the ones created during the previous run, thus saving time and CPU. =head2 Creating a sandbox from already installed binaries The script C tries to create a sandbox using already installed binaries. Since these binaries can be in several different places, the script creates a container with symbolic links, where the binaries (their links, actually) are arranged as MySQL Sandbox expects them to be. To use this version, change directory to a place where you want to store this symbolic links container, and invoke make_sandbox_from_installed X.X.XX [options] where X.X.XX is the version number. You can then pass any options accepted by make_sandbox. =head2 Defaults and shortcuts If you use sandboxes often, instead of pointing to a tarball you can set a directory containing expanded tarballs. By default, the sandbox looks under $HOME/opt/mysql and /opt/mysql The expanded tarballs must be named with the full version. e.g. $HOME/opt/mysql/5.0.64 /opt/mysql/5.1.24 If you have such an organization, then you can invoke every sandbox script with this abridged syntax: make_sandbox 5.0.64 make_replication_sandbox 5.1.25 make_multiple_custom_sandbox 5.0.64 5.1.25 If you use some options frequently, it would make sense to add them to the default option file, which is $HOME/.msandboxrc =head2 Fine tuning Every sandbox script will give you additional information if you invoke it with the "--help" option. When creating a single sandbox, you can pass to the new server most any option that can be used in a my.cnf file, in addition to specific sandbox options. Multiple and replication sandboxes, for example, accept a --how_many_slaves=X or --how_many_nodes=X option, allowing you to create very large groups. =head2 SANDBOX HOME Unless you override the defaults, sandboxes are created inside a directory that servers two purposes: =over 3 =item * further isolates the sandboxes, and keep them under easy control if you are in the habit of creating many of them; =item * provides a set of handy super-commands, which can be passed to all the sandboxes. Running "$SANDBOX_HOME/stop_all" you will stop all servers of all sandboxes, single or groups, below that directory. =back =head1 USING A SANDBOX Change directory to the newly created one (default: $SANDBOX_HOME/msb_VERSION for single sandboxes) The sandbox directory of the instance you just created contains some handy scripts to manage your server easily and in isolation. =over 3 =item start =item restart =item stop "./start", "./restart", and "./stop" do what their name suggests. C and C accept parameters that are eventually passed to the server. e.g.: ./start --skip-innodb ./restart --event-scheduler=disabled =item use "./use" calls the command line client with the appropriate parameters, =item clear "./clear" stops the server and removes everything from the data directory, letting you ready to start from scratch. =item multiple server sandbox On a replication sandbox, you have the same commands, with a "_all" suffix, meaning that you propagate the command to all the members. Then you have "./m" as a shortcut to use the master, "./s1" and "./s2" to access the slaves (and "s3", "s4" ... if you define more). In group sandboxes without a master slave relationship (circular replication and multiple sandboxes) the nodes can be accessed by ./n1, ./n2, ./n3, and so on. =over 3 =item start_all =item restart_all =item stop_all =item use_all =item clear_all =item m =item s1,s2 =back =back =head2 Database users There are 2 database users installed by default: +-----------------+-------------+-------------------------------+ | user name | password | privileges | +-----------------+-------------+-------------------------------+ | root@localhost | msandbox | all on *.* with grant option | | msandbox@% | msandbox | all on *.* | | rsandbox@127.% | rsandbox | REPLICATION SLAVE | | | | (only replication sandboxes) | +-----------------+-------------+-------------------------------+ =head2 Ports and sockets Ports are created from the server version. a 5.1.25 server will use port 5125, unless you override the default. Replicated and group sandboxes add a delta number to the version figure, to avoid clashing with single installations. (note: ports can be overridden using -P option during install) +--------+-----------------------------+ | port | socket | +--------+-----------------------------+ | 3310 | /tmp/mysql_sandbox3310.sock | +--------+-----------------------------+ =head2 Searching for free ports MySQL Sandbox uses a fairly reasonable system of default ports that guarantees the usage of unused ports most of the times. If you are creating many sandbozes, however, especially if you want several sandboxes using the same versions, collisions may happen. In these cases, you may ask for a port check before installing, thus making sure that your sandbox is really not conflicting with anything. =head3 Single sandbox port checking The default behavior when asking to install a sandbox over an existing one is to abort. If you specify the C<--force> option, the old sandbox will be saved as 'old_data' and a new one created. Instead, using the C<--check_port> option, MySQL Sandbox searches for the first available unused port, and uses it. It will also create a non conflicting data directory. For example make_sandbox 5.0.79 # creates a sandbox with port 5079 under $SANDBOX_HOME/msb_5_0_79 A further call to the same command will be aborted unless you specify either C<--force> or C<--check_port>. make_sandbox 5.0.79 -- --force # Creates a sandbox with port 5079 under $SANDBOX_HOME/msb_5_0_79 # The contents of the previous data directory are saved as 'old_data'. make_sandbox 5.0.79 -- --check_port # Creates a sandbox with port 5080 under $SANDBOX_HOME/msb_5_0_79_a make_sandbox 5.0.79 -- --check_port # Creates a sandbox with port 5081 under $SANDBOX_HOME/msb_5_0_79_b Notice that this option is disabled when you use a group sandbox (replication or multiple). Even if you set NODE_OPTIONS=--check_port, it won't be used, because every group sandbox invokes make_sandbox with the --no_check_port option. =head3 Multiple sandbox port checking When you create a multiple sandbox (make_replication_sandbox, make_multiple_sandbox, make_multiple_custom_sandbox) the default behavior is to overwrite the existing sandbox without asking for confirmation. The rationale is that a multiple sandbox is definitely more likely to be a created only for testing purposes, and overwriting it should not be a problem. If you want to avoid overwriting, you can specify a different group name (C<--replication_directory> C<--group_directory>), but this will use the same base port number, unless you specify C<--check_base_port>. make_replication_sandbox 5.0.79 # Creates a replication directory under $SANDBOX_HOME/rsandbox_5_0_79 # The default base_port is 7000 make_replication_sandbox 5.0.79 # Creates a replication directory under $SANDBOX_HOME/rsandbox_5_0_79 # overwriting the previous one. The default base port is still 7000 # WRONG make_replication_sandbox --check_base_port 5.0.79 # Creates a replication directory under $SANDBOX_HOME/rsandbox_5_0_79 # overwriting the previous one. # WRONG make_replication_sandbox --replication_directory=newdir 5.0.79 # Created a replication directory under $SANDBOX_HOME/newdir. # The previous one is preserved, but the new sandbox does not start # because of port conflict. # RIGHT make_replication_sandbox --replication_directory=newwdir \ --check_base_port 5.0.79 # Creates a replication directory under $SANDBOX_HOME/newdir # The previous one is preserved. No conflicts happen =head2 Environment variables All programs in the Sandbox suite recognize and use the following variables: * HOME the user's home directory; ($HOME) * SANDBOX_HOME the place where the sandboxes are going to be built. ($HOME/sandboxes by default) * USER the operating system user; * PATH the execution path; * if SBDEBUG if set, the programs will print debugging messages In addition to the above, make_sandbox will use * SANDBOX_BINARY or BINARY_BASE the directory containing the installation server binaries (default: $HOME/opt/mysql) make_replication_sandbox will recognize the following * MASTER_OPTIONS additional options to be passed to the master * SLAVE_OPTIONS additional options to be passed to each slave * NODE_OPTIONS additional options to be passed to each node The latter is also recognized by make_multiple_custom_sandbox and make_multiple_sandbox The test suite, C, recognizes two environment variables * TEST_SANDBOX_HOME, which sets the path where the sandboxes are installed, if the default $HOME/test_sb is not suitable. It is used when you test the package with 'make test' * PRESERVE_TESTS. If set, this variable prevents the removal of test sandboxes created by test_sandbox. It is useful to inspect sandboxes if a test fails. =head2 msb - the Sandbox shortcut When you have many sandboxes, even the simple exercise of typing the path to the appropriate 'use' script can be tedious and seemingly slow. If saving a few keystrokes is important, you may consider using C, the sandbox shortcut. You invoke 'msb' with a version number, without dots or underscores. The shortcut script will try its best at finding the right directory. $ msb 5135 # same as calling # $SANDBOX_HOME/msb_5_1_35/use Every option that you use after the version is passed to the 'use' script. $ msb 5135 -e "SELECT VERSION()" # same as calling # $SANDBOX_HOME/msb_5_1_35/use -e "SELECT VERSION()" Prepending a "r" to the version number indicates a replication sandbox. If the directory is found, the script will call the master. $ msb r5135 # same as calling # $SANDBOX_HOME/rsandbox_5_1_35/m To use a slave, use the corresponding number immediately after the version. $ msb r5135 2 # same as calling # $SANDBOX_HOME/rsandbox_5_1_35/s2 Options for the destination script are added after the node indication. $ msb r5135 2 -e "SELECT 1" # same as calling # $SANDBOX_HOME/rsandbox_5_1_35/s2 -e "SELECT 1" Similar to replication, you can call multiple sandboxes, using an 'm' before the version number. $ msb m5135 # same as calling # $SANDBOX_HOME/multi_msb_5_1_35/n1 $ msb m5135 2 # same as calling # $SANDBOX_HOME/multi_msb_5_1_35/n2 If your sandbox has a non-standard name and you pass such name instead of a version, the script will attempt to open a single sandbox with that name. $ msb testSB # same as calling # $SANDBOX_HOME/testSB/use If the identified sandbox is not active, the script will attempt to start it. This shortcut script doesn't deal with any sandbox script other than the ones listed in the above examples. But the msb can do even more. If you invoke it with a dotted version number, the script will run the appropriate make*sandbox script and then use the sandbox itself. $ msb 5.1.35 # same as calling # make_sandbox 5.1.35 -- --no_confirm # and then # $SANDBOX_HOME/msb_5_1_35/use It works for group sandboxes as well. $ msb r5.1.35 # same as calling # make_replication_sandbox 5.1.35 # and then # $SANDBOX_HOME/rsandbox_5_1_35/m And finally, it also does What You Expect when using a tarball instead of a version. $ msb mysql-5.1.35-YOUR_OS.tar.gz # creates and uses a single sandbox from this tarball $ msb r mysql-5.1.35-YOUR_OS.tar.gz # creates and uses a replication sandbox from this tarball $ msb m mysql-5.1.35-YOUR_OS.tar.gz # creates and uses a multiple sandbox from this tarball Using a MySQL server has never been easier. =head1 SBTool the Sandbox helper The Sandbox Helper, C, is a tool that allows administrative operations on already existing sandboxes. It does a number of important tasks that are not available at creation time or that would require too much manual labor. usage: sbtool [options] -o --operation (s) <> - what task to perform 'info' returns configuration options from a Sandbox 'copy' copies data from one Sandbox to another 'ports' lists ports used by the Sandbox 'tree' creates a replication tree 'move' moves a Sandbox to a different location 'range' finds N consecutive ports not yet used by the Sandbox 'port' Changes a Sandbox port 'delete' removes a sandbox completely 'preserve' makes a sandbox permanent 'unpreserve' makes a sandbox NOT permanent 'plugin' installs a given plugin -s --source_dir (s) <> - source directory for move,copy -d --dest_dir (s) <> - destination directory for move,copy -n --new_port (s) <> - new port while moving a sandbox -u --only_used (-) <> - for "ports" operation, shows only the used ones -i --min_range (i) <5000> - minimum port when searching for available ranges -x --max_range (i) <64000> - maximum port when searching for available ranges -z --range_size (i) <10> - size of range when searching for available port range -f --format (s) - format for "ports" and "info" 'perl' fully structured information in Perl code 'text' plain text dump of requested information -p --search_path (s) - search path for ports and info -a --all_info (-) <> - print more info for "ports" operation --tree_nodes (s) <> - description of the tree (x-x x x-x x|x x x|x x) --mid_nodes (s) <> - description of the middle nodes (x x x) --leaf_nodes (s) <> - description of the leaf nodes (x x|x x x|x x) --tree_dir (s) <> - which directory contains the tree nodes --plugin (s) <> - which plugin needs to be installed --plugin_file (s) <> - which plugin template file should be used -v --verbose (-) <> - prints more info on some operations -h --help (-) <1> - this screen =head2 sbtool - Informational options =head3 sbtool -o info Returns configuration options from a Sandbox (if specified) or from all sandboxes under $SANDBOX_HOME (default). You can use C<--search_path> to tell sbtool where to start. The return information is formatted as a Perl structure. =head3 sbtool -o ports Lists ports used by the Sandbox. Use C<--search_path> to tell sbtool where to start looking (default is $SANDBOX_HOME). You can also use the C<--format> option to influence the outcome. Currently supported are only 'text' and 'perl'. If you add the C<--only_used> option, sbtool will return only the ports that are currently open. =head3 sbtool -o range Finds N consecutive ports not yet used by the Sandbox. It uses the same options used with 'ports' and 'info'. Additionally, you can define the low and high boundaries by means of C<--min_range> and C<--max_range>. The size of range to search is 10 ports by default. It can be changed with C<--range_size>. =head2 sbtool - modification options =head3 sbtool -o port Changes port to an existing Sandbox. This requires the options C<--source_dir> and C<--new_port> to complete the task. If the sandbox is running, it will be stopped. =head3 sbtool -o copy Copies data from one Sandbox to another. It only works on B sandboxes. It requires the C<--source_dir> and C<--dest_dir> options to complete the task. Both Source and destination directory must be already installed sandboxes. If any of them is still running, it will be stopped. If both source and destination directory point to the same directory, the command is not performed. At the end of the operation, all the data in the source sandbox is copied to the destination sandbox. Existing files will be overwritten. It is advisable, but not required, to run a "./clear" command on the destination directory before performing this task. =head3 sbtool -o move Moves a Sandbox to a different location. Unlike 'copy', this operation acts on the whole sandbox, and can move both single and multiple sandboxes. It requires the C<--source_dir> and C<--dest_dir> options to complete the task. If the destination directory already exists, the task is not performed. If the source sandbox is running, it will be stopped before performing the operation. After the move, all paths used in the sandbox scripts will be changed. =head3 sbtool -o tree Creates a replication tree, with one master, one or more intermediate level slaves, and one or more leaf node slaves for each intermediate level. To create the tree, you need to create a multiple nodes sandbox (using C) and then use C with the following options: * --tree_dir , containing the sandbox to convert to a tree * --master_node, containing the node that will be master * --mid_nodes, with a list of nodes for the intermediate level * --leaf_nodes, with as many lists as how many mid_nodes Each list is separated from the next by a pipe sign (|). Alternatively, you can use the C<--tree_nodes> option to describe all the tree at once. For example, in a sandbox with 8 nodes, to define 1 as master node, nodes 2 and 3 as middle nodes, nodes 4, 5, and 6 as slaves of node 2 and nodes 7 and 8 as slaves of node 3, you can use either of the following: sbtool --tree_dir=/path/to/source \ --master_node=1 \ --mid_nodes='2 3' --leaf_nodes='4 5 6|7 8' sbtool --tree_dir=/path/to/source \ --tree_nodes='1 - 2 3 - 4 5 6|7 8' =head3 sbtool -o preserve Makes a sandbox permanent. It requires the C<--source_dir> option to complete the task. This command changes the 'clear' command within the requested sandbox, disabling its effects. The sandbox can't be erased using 'clear' or 'clear_all'. The 'delete' operation of sbtool will skip a sandbox that has been made permanent. =head3 sbtool -o unpreserve Makes a sandbox NOT permanent. It requires the C<--source_dir> option to complete the task. This command cancels the changes made by a 'preserve' operation, making a sandbox erasable with the 'clear' command. The 'delete' operation can be performed successfully on an unpreserved sandbox. =head3 sbtool -o delete Removes a sandbox completely. It requires the C<--source_dir> option to complete the task. The requested sandbox will be stopped and then deleted completely. WARNING! No confirmation is asked! =head3 sbtool -o plugin Installs a given plugin into a sandbox. It requires the C<--source_dir> and C<--plugin> options to complete the task. The plugin indicated must be defined in the plugin template file, which is by default installed in C<$SANDBOX_HOME>. Optionally, you can indicate a different plugin template with the C<--plugin_file> option. By default, sbtool looks for the plugin template file in the sandbox directory that is the target of the installation. If it is not found there, it will look at C<$SANDBOX_HOME> before giving up with an error. =head4 Plugin template The Plugin template is a Perl script containing the definition of the templates you want to install. Each plugin must have at least one target B, which could be one of I, I, or I. It is allowed to have more than one target types in the same plugin. Each server type, in turn, must have at least one section named B, an array reference containing the list of the actions to perform. Such actions can be regular scripts in each sandbox (start, stop, restart, clear) or one of the following template sections: =over 3 =item options_file It is the list of lines to add to an options file, under the C<[mysqld]> label. =item sql_commands It is a list of queries to execute. Every query must have appropriate semicolons as required. If no semicolon are found in the list, no queries are executed. =item startup_file It is a file, named I, to be created under the data directory. It will contain the lines indicated in this section. You must remember to add a line 'init-file=startup.sql' to the options_file section. =back =head1 TESTING =head2 test_sandbox The MySQL Sandbox comes with a test suite, called test_sandbox, which by default tests single,replicated, multiple, and custom installations of MySQL version 5.0.77 and 5.1.32.You can override the version being tested by means of command line options: test_sandbox --versions=5.0.67,5.1.30 or you can specify a tarball test_sandbox --versions=/path/to/mysql-tarball-5.1.31.tar.gz test_sandbox --tarball=/path/to/mysql-tarball-5.1.31.tar.gz You can also define which tests you want to run: test_sandbox --tests=single,replication =head2 Test isolation The tests are not performed in the common C<$SANDBOX_HOME> directory, but on a separate directory, which by default is C<$HOME/test_sb>. To avoid interferences, before the tests start, the application runs the C<$SANDBOX_HOME/stop_all> command. The test directory is considered to exist purely for testing purposes, and it is erased several times while running the suite. Using this directory to store valuable data is higly risky. =head2 Tests during installation When you build the package and run make test test_sandbox is called, in addition to many other tests in the ./t directory, and the tests are performed on a temporary directory under C<$INSTALLATION_DIRECTORY/t/test_sb>. By default, version 5.6.26 is used. If this version is not found in C<$HOME/opt/mysql/>, the test is skipped. You can override this option by setting the TEST_VERSION environment variable. TEST_VERSION=5.7.9 make test TEST_VERSION=$HOME/opt/mysql/5.7.9 make test TEST_VERSION=/path/to/myswl-tarball-5.7.9.tar.gz make test =head2 User defined tests Starting with version 2.0.99, you can define your own tests, and run them by $ test_sandbox --user_test=file_name =head3 simplified test script Inside your test file, you can define test actions. There are two kind of tests: shell and sql the test type is defined by a keyword followed by a colon. The 'shell' test requires a 'command', which is passed to a shell. The 'expected' label is a string that you expect to find within the shell output. If you don't expect anything, you can just say "expected = OK", meaning that you will be satisfied with a ZERO exit code reported by the operating system. The 'msg' is the description of the test that is shown to you when the test runs. shell: command = make_sandbox 5.1.30 -- --no_confirm expected = sandbox server started msg = sandbox creation The 'sql' test requires a 'path', which is the place where the test engine expects to find a 'use' script. The 'query' is passed to the above mentioned script and the output is captured for further processing. The 'expected' parameter is a string that you want to find in the query output. The 'msg' parameter is like the one used with the 'shell' test. sql: path = $SANDBOX_HOME/msb_5_1_30 query = select version() expected = 5.1.30 msg = checking version All strings starting with a $ are expanded to their corresponding environment variables. For example, if $SANDBOX_HOME is /home/sb/tests, the line command = $SANDBOX_HOME/msb_5_1_30/stop will expand to: command = /home/sb/tests/msb_5_1_30/stop =head3 Perl based test scripts In addition to the internal script language, you can also define perl scripts, which will be able to use the $sandbox_home global variable and to call routines defined inside test_sandbox. (see list below) To be identified as a Perl script, the user defined test must have the extension ".sb.pl" =over 3 =item ok_shell() The C function requires a hash reference containing the following labels: A 'command', which is passed to a shell. The 'expected' label is a string that you expect to find within the shell output. If you don't expect anything, you can just say "expected = OK", meaning that you will be satisfied with a ZERO exit code reported by the operating system. The 'msg' is the description of the test that is shown to you when the test runs. ok_shell($hashref) ok_shell({ command => 'make_sandbox 5.1.30 --no_confirm', expected => 'sandbox server started', msg => 'sandbox creation', }) =item ok_sql() The C function requires a hashref containing the following labels: A 'path', which is the place where the test engine expects to find a 'use' script. The 'query' is passed to the above mentioned script and the output is captured for further processing. The 'expected' parameter is a string that you want to find in the query output. The 'msg' parameter is like the one used with the ok_exec function. =item get_bare_version() This function accepts one parameter, which can be either a MySQL tarball name or a version, and returns the bare version found in the input string. If called in list mode, it returns also a normalized version string with dots replaced by underscores. my $version = get_bare_version('5.1.30'); # returns '5.1.30' my $version = get_bare_version('mysql-5.1.30-OS.tar.gz'); # returns '5.1.30' my ($version,$dir_name) = get_bare_version('mysql-5.1.30-OS.tar.gz'); # returns ('5.1.30', '5_1_30') =item ok This is a low level function, similar to the one provided by Test::More. You should not need to call this one directly, unless you want to fine tuning a test. See the test script t/start_restart_arguments.sb.pl as an example =back =head1 REQUIREMENTS To use this package you need at least the following: =over 3 =item * Linux or Mac OSX operating system (it may work in other *NIX OSs, but has not been tested) =item * A binary tarball of MySQL 3.23 or later =item * Perl 5.8.1 or later =item * Bash shell =back =head1 COPYRIGHT Version 3.1 Copyright (C) 2006-2015 Giuseppe Maxia Home Page http://github.com/datacharmer =head1 LEGAL NOTICE Copyright 2006-2015 Giuseppe Maxia Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. MySQL-Sandbox-3.1.04/lib/MySQL/Sandbox/Recipes.pm000644 000765 000024 00000071343 12631363502 021311 0ustar00gmaxstaff000000 000000 package MySQL::Sandbox::Recipes; our $VERSION="3.1.04"; 1; __END__ =head1 NAME MySQL::Sandbox::Recipes - A cookbook for MySQL Sandbox =head1 PURPOSE This package is a collection of HOW-TO brief tutorials and recipes for MySQL Sandbox =head1 Installing MySQL::Sandbox All the recipes here need the MySQL Sandbox L. Therefore you need to install it, to be able to follow these recipes. For a general description of the application, see L. A presentation on this matter is available at Slideshare L =head2 the easy way - as root This is so easy, that I am almost ashamed to show it. Anyway, here goes. $ sudo su - # cpan MySQL::Sandbox =head2 the ambitious way - as unprivileged user It is not difficult, but it requires some steps that depend on your environment. To simplify the example, let's assume that you are using perl 5.8.8 and you want to install in $HOME/usr/local. =over 3 =item 1 Download MySQL Sandbox tarball from cpan =item 2 Set the variables that you will need mkdir -p $HOME/usr/local export PATH=$HOME/usr/local/bin:$PATH export PERL5LIB=$HOME/usr/local/lib/perl5/site_perl/5.8.8 =item 3 Build and install perl Makefile.PL PREFIX=$HOME/usr/local make make test make install =back It is a bit complex, but you need to do the setup only once. After that, you can use MySQL Sandbox in your user space. Another solution, which can be habdy if you use a box without Perl and without root access, is to install Perl in your user space, and then you can use CPAN to install any package in your user space. =head1 SINGLE SERVER RECIPES =head2 Creating a single sandbox =over 3 =item 1 Download or build a MySQL server tarball. Its name is something like mysql-X.X.X-Your_Operating_System.tar.gz =item 2 Make the sandbox make_sandbox /path/to/mysql-X.X.X-Your_Operating_System.tar.gz Notice that this command will expand the tarball into a directory C, located in the same path where tghe tarball is. If you want to expand in a centralized directory, see the next recipe. If you have already a centralized repository for your binaries (see next recipe), then you can create a sandbox even more easily: make_sandbox 5.1.34 make_replication_sandbox 5.1.34 =back =head2 Easily creating more sandboxes after the first one If you want to reuse the same binaries more than once, you can set up a repository for such binaries, under $SANDBOX_BINARY, which by default is $HOME/opt/mysql If you have such a directory, you have two choices. =over 3 =item manually Expand the tarball, and move it under $HOME/opt/mysql (or set $SANDBOX_BINARY to a path that suits you better). Name the directory with the version number. For example: cd $HOME/opt/mysql gunzip -c /path/to/mysql-5.1.34-osx10.5-x86.tar.gz | tar -xf - mv mysql-5.1.34-osx10.5-x86 5.1.34 Now, next time you want to install a sandbox using 5.1.34, all you need to do is say make_sandbox 5.1.34 =item automatically If you want to combine installation and centralization of the binaries in one go, you can: make_sandbox --export_binaries /path/to/mysql-5.1.34-osx10.5-x86.tar.gz The expanded tarball is copied to the $SANDBOX_BINARY path, and you can refer to the version number only for future installations. =back =head2 Using a single sandbox When you create a sandbox, the last line of the application output tells you where it was created. If you don't remember where it is, the default location is $HOME/sandboxes/msb_X_X_XX, where X_X_XX is the version number. For example if you have installed make_sandbox 5.1.34 your sandbox is under $HOME/sandboxes/msb_5_1_34. To use it, move to that directory and invoke the C<./use> script. This script is a shortcut to invoke the mysql command line client, with all the appropriate parameters. ./msb_5_1_34/use Welcome to the MySQL monitor. Commands end with ; or \g. Your MySQL connection id is 1 Server version: 5.1.34 MySQL Community Server (GPL) . Type 'help;' or '\h' for help. Type '\c' to clear the current input statement. . mysql [localhost] {msandbox} ((none)) > The default user is 'msandbox' and the password is 'msandbox'. The same password is also used by the 'root' account. The 'use' script accepts all the additional options and commands that you would use with the mysql client. For example: ./use -e 'show schemas' +--------------------+ | Database | +--------------------+ | information_schema | | mysql | | test | +--------------------+ ./use -N -B -e 'select version()' 5.1.34 You don't need to be inside the sandbox to use this script. You can invoke it with a relative or absolute path. $HOME/sandboxes/msb_5_1_34/use -e 'select version()' +-----------+ | version() | +-----------+ | 5.1.34 | +-----------+ Notice that this script is created when the sandbox is installed. It is heavily customized for that sandbox only, and it is not replaceable by the same script from another sandbox. Even if you move it to another directory, it will still refer to the sandbox in which it was created. See 'moving a sandbox' for a safe way of moving a sandbox with all its scripts to a different directory. =head2 Creating a single sandbox with user-defined port and directory When you create a sandbox, you can fine tune the final product by adding options. You can list of all the available options easily: low_level_make_sandbox --help You can pass any of the options listed to C. In particular, since we need to change the port and directory, here's the deed: make_sandbox 5.1.34 # installs on $SANDBOX_HOME/msb_5_1_34 with port 5134 make_sandbox 5.1.34 -- --sandbox_port=7800 --sandbox_directory=mickeymouse # installs on $SANDBOX_HOME/mickeymouse with port 7800 See the next recipe for an automatic way of getting a different port and directory. =head2 Creating a single sandbox with automatic port checking make_sandbox 5.1.34 -- --check_port This option will check if port 5134 is used. If it is, it will check the next available port, until it finds a free one. In the previous statement context, 'free' means not only 'in use', but also allocated by another sandbox that is currently not running. If the directory msb_5_1_34 is used, the sandbox is created in msb_5_1_34_a. The application keeps checking for free ports and unused directories until it finds a suitable combination. Notice that this option is disabled when you use a group sandbox (replication or multiple). Even if you set NODE_OPTIONS=--check_port, it won't be used, because every group sandbox invokes make_sandbox with the --no_check_port option. =head2 Creating a single sandbox with a specific option file make_sandbox 5.1.34 -- --my_file=large This option installs the option file template my-large.cnf, which ships with every MySQL release. Similarly, you can choose 'small' or 'huge' to load the appropriate template. If you have your favorite option file, you can specify the full path to it make_sandbox 5.1.34 -- --my_file=/path/to/my_smart.cnf In all cases, the sandbox installer skips all the options that are necessary to keep the sandbox isolated and efficient (user, port,socket,datadir,basedir). =head2 Creating a single sandbox from a source directory After you have compiled MySQL from source, you can create a sandbox with the new binaries: make_sandbox_from_source $PWD single [options] The options are the same that you can pass to make_sandbox. This script creates a tarball, and then invokes make_sandbox to finish the job. =head2 Starting or restarting a single sandbox with temporary options Every single server sandbox has a 'start' script, which does what the name suggests. Not only that, but you can start a sandbox with additional parameters for the mysqld daemon. ./start --key-buffer=3G The 'restart' script accepts parameters in the same way. While 'start' only works when the sandboxed server is not running, 'restart' makes sure that the server is stopped, and then invokes 'start' with the optional parameters. =head2 Stopping a sandbox Inside every single sandbox there are two scripts that can stop a sandbox. ./stop The 'stop' script attempts a clean stop, using mysqladmin. This works most of the time, especially if you are using a GA release. ./send_kill The 'send_kill' script achieve the same result, but with a different path. First, it tries to stop the sandboxed server nicely, by sending a C to the server PID. If this fails, after a reasonable timeout, it sends a deadly C and removes the PID file. This brutal method is not recommended for general usage, but it is sometimes necessary when dealing with servers in early stages of their development. =head2 Cleaning up a sandbox ./clear The 'clear' script will empty the data directory, trying to clean the system as much as possible. If the server is running when you invoke the script, it will issue a C query for each schema. It will also truncate the general and slow query log tables, if they exist. If the server is not running, 'clear' will clean up the data directory as best as it can. Notice however that invoking 'clear' when the server is not running will not remove stored routines and events. WARNING! No confirmation is asked! The data will be gone in 1 second. =head2 Copying sandbox contents to another Using 'sbtool', the Sandbox helper, this task is easy to perform. You need two sandboxes. This command cannnot copy to an arbitrary directory, but only to an existing sandbox. The first sandbox is where the data is stored. You need to use the C<--source_dir> option (or C<-s> for short). The second directory, identified with C<--dest_dir>, (or C<-d>) is the place where the data is copied. WARNING! the destination data is overwritten! This command skips binary logs, relay logs, and general logs. sbtool -o copy \ -s /path/to/source/sandbox \ -d /path/to/destination/sandbox Some important points to remember: =over 3 =item * This command only copies from a single sandbox to another. If you want to copy from a masterto several slaves, you need to run the command multiple times. =item * Before copying, this command stops both source and destination sandbox. =back =head2 Moving a sandbox sbtool -o move \ -s /path/to/source/sandbox \ -d /path/to/destination/directory This command stops the sandbox, moves it to the requested directory, and then changes all the paths in the scripts, to refer to the new directory. If the destination directory already exists, the command fails. =head2 Changing port to an existing sandbox sbtool -o port \ -s /path/to/source/sandbox \ --new_port=XXXX THis is similar to moving a sandbox, except that the directory is not changed. The sandbox is stopped, and the port changed in all the scripts. =head2 Removing a sandbox completely sbtool -o delete \ -s /path/to/source/sandbox This is a combination of using the 'clear' script and removing the sandbox. There is a safety check, though. If the sandbox is a permanent one (see next recipe), the operation aborts. Otherwise, the script calls 'clear' (clear_all if it is a group sandbox) and then removes all the contents. WARNING! No confirmation is asked! The data will be gone in 1 second. =head2 Making a sandbox permanent MySQL Sandbox has been created with testing in mind. As such, the sandboxes are expendable, and there are some commands to get rid of them easily and quickly. However, you don't want always to do this. Sometimes, you need to keep the data for some time, to record it, or to copy it somewhere, or to use it for some similar testing. Whatever the reason, in these cases you don't want your data to disappear accidentally. The 'preserve' command, part of the sbtool, disables the 'clear' script in your sandbox, to avoid unpleasant "oh no" moments. Notice that nothing will protect you against hastily typed 'DROP DATABASE' queries! If you really need your data around, make a copy! sbtool -o preserve \ -s /path/to/source/sandbox If you change your mind, invoking sbtool with the 'unpreserve' operation, makes the sandbox erasable again. sbtool -o unpreserve \ -s /path/to/source/sandbox =head2 Starting and stopping a sandbox when the host server starts There is no built-in solution for this recipe. Every operating system has its own method to launch applications at start up. The important point is that probably you don't need it. MySQL Sandbox is a tool for testing, aiming at creating temporary MySQL servers, and as such you should not need to launch a sandbox at start up. If you really need it, the MySQL manual explain how to launch at startup the main instance of the database. =head2 Installing a sandbox from already installed binaries make_sandbox_from_installed VERSION [options] This script (introduced in 2.0.99e) creates a repository of symbolic links from already installed binaries, arranging them in a way that the MySQL Sandbox easily recognizes. You should move to a directory where you want to keep this repository, before invoking this script. For example: mkdir -p $HOME/opt/mysql cd $HOME/opt/mysql make_sandbox_from_installed 5.1.34 --no_confirm After this call, you can then install sandboxes (single or multiple) with a simple make_{replication_|multiple_}sandbox 5.1.34 =head1 MULTIPLE SERVER RECIPES =head2 Creating a standard replication sandbox make_replication_sandbox /path/to/tarball5.1.34.tar.gz As easy as making a single sandbox, this command creates a replication system with one master an two slaves. If you have set the repository under $SANDBOX_BINARY (see L), then you can also say make_replication_sandbox 5.1.34 If you want a different number of slaves, you can add an option make_replication_sandbox --how_many_slaves=5 5.1.34 =head2 Using a replication sandbox When you create a replication sandbox, the last line of the application output tells you where it was created. If you don't remember where it is, the default location is $HOME/sandboxes/rsandbox_X_X_XX, where X_X_XX is the version number. For example if you have installed make_replication_sandbox 5.1.34 your sandbox is under $HOME/sandboxes/rsandbox_5_1_34. To use it, move to that directory and invoke one of these scripts: * ./m for the master * ./s1 for the first slave * ./s2 for the second slave, s3 for the third one, and so on * ./use_all to send a command to the master and all slaves * ./check_slaves to see as a quick glance if the slaves are working All the above scripts are shortcuts to the 'use' script in the appropriate directory. The 'use' script was described in the section dedicated to single server recipes. =head2 Creating a circular replication sandbox To create a circular replication system, you use the same command used for standard replication, but you add an option to indicate that you want a circular topology. make_replication_sandbox --circular=4 /path/to/tarball5.1.34.tar.gz The above command creates a system with 4 nodes, where node 1 is master of 2, node 2 is master of 3, node 3 is master of 4, and node 4, to close the circle, is master of 1. If you have a binary repository under $SANDBOX_BINARY, you can use the simplified call: make_replication_sandbox --circular=4 5.1.34 =head2 Using a circular sandbox Same as using a replication sandbox (see above), but there are no 'm' and 's#' scripts. Instead, there are 'n#' scripts, to access node 1 (n1), node 2, (n2) and so on. You may try this: $ ./n1 -e 'create table test.t1 (i int)' $ ./n3 -e 'insert into test.t1 values (3)' $ ./use_all 'select * from test.t1' # server: 1: i 3 # server: 2: i 3 # server: 3: i 3 # server: 4: i 3 =head2 Creating a group of unrelated sandboxes (same version) make_multiple_sandbox /path/to/tarball make_multiple_sandbox --how_many_nodes=4 /path/to/tarball A group of unrelated sandboxes is a set of three or more servers installed under the same directory. What is the purpose of this? It is useful whenever you need to play with several servers without being tied by the master/slave relationship. One possible reason is to try new replication schemes with a clean setup. Or you may want to test the Federated engine. Another common usage is when you need to test different approaches to the same problem, and you want to compare results quickly. =head2 Creating a group of unrelated sandboxes (different versions) make_multiple_custom_sandbox /path/to/tarball5.1.34 /path/to/tarball5.0.77 make_multiple_custom_sandbox 5.1.34 5.0.77 5.4.0 Similar to the previous one, the composite group is a collection of servers of different versions, all under the same directory. It can be useful when you want to compare some scheme in different versions, and automate the operations as much as possible. =head2 Using a group of sandboxes Same as using a replication sandbox (see above), but there are no 'm' and 's#' scripts. Instead, there are 'n#' scripts, to access node 1 (n1), node 2, (n2) and so on. A group of sandboxes is easily manged with the 'use_all' script. For example, you may want to pass a SQL instruction to all the servers ./use_all 'select something from dbname.tablename where x=1' Or you want to execute a SQL script for each server ./use_all 'source somescript.sql' The internal organization of the directory makes it easy to do more complex operations with all the servers within the group. For example, if you want to measure the speed of execution of the same statement for each server (assuming that you have different setups for each one), you can create a shell script: ./stop_all for N in 1 2 3 do echo "processing node $N" ./node$N/start --some_mysqld_option=somevalue time ./node$N/use -e 'select something_heavy from somedb.sometable' ./node$N/stop done =head2 Creating a group sandbox with port checking When you create a multiple sandbox (make_replication_sandbox, make_multiple_sandbox, make_multiple_custom_sandbox) the default behavior is to overwrite the existing sandbox without asking for confirmation. The rationale is that a multiple sandbox is definitely more likely to be a created only for testing purposes, and overwriting it should not be a problem. If you want to avoid overwriting, you can specify a different group name (C<--replication_directory> C<--group_directory>), but this will use the same base port number, unless you specify C<--check_base_port>. make_replication_sandbox 5.0.79 # Creates a replication directory under $SANDBOX_HOME/rsandbox_5_0_79 # The default base_port is 7000 make_replication_sandbox 5.0.79 # Creates a replication directory under $SANDBOX_HOME/rsandbox_5_0_79 # overwriting the previous one. The default base port is still 7000 # WRONG make_replication_sandbox --check_base_port 5.0.79 # Creates a replication directory under $SANDBOX_HOME/rsandbox_5_0_79 # overwriting the previous one. # WRONG make_replication_sandbox --replication_directory=newdir 5.0.79 # Created a replication directory under $SANDBOX_HOME/newdir. # The previous one is preserved, but the new sandbox does not start # because of port conflict. # RIGHT make_replication_sandbox --replication_directory=newwdir \ --check_base_port 5.0.79 # Creates a replication directory under $SANDBOX_HOME/newdir # The previous one is preserved. No conflicts happen =head2 Creating a group sandbox with a specific option file When you create a group sandbox, make_sanbox is invoked several times, with a predefined set of options. You can add options for each node by means of environmental variables. If you create a replication sandbox, you can set different options for the master and for the slaves: export MASTER_OPTIONS="--my_file=huge" export SLAVE_OPTIONS="--my_file=large" make_replication_sandbox 5.1.34 export MASTER_OPTIONS="--my_file=/path/to/my.cnf" export SLAVE_OPTIONS="--my_file=/path/to/my_other.cnf" make_replication_sandbox 5.1.34 If you don't need the distinction, then you can define the same option for all nodes at once: export NODE_OPTIONS="--my_file=large" make_replication_sandbox 5.1.34 For non-replication group sandboxes (or for circular replication), $NODE_OPTION is the appropriate way of setting options. export NODE_OPTIONS="--my_file=large" make_multiple_sandbox 5.1.34 =head2 Creating a group sandbox from a source directory Same as for a single sandbox, but use the 'replication' or 'multiple' keyword when calling the script. make_sandbox_from_source $PWD replication [options] make_sandbox_from_source $PWD multiple [options] =head2 Starting or restarting a group sandbox with temporary options When you want to restart a group of sandboxes with some temporary options, all you need to do is to pass the option to the command line of ./start_all (if the group was not running) or ./restart_all. ./start_all --mysqld=mysqld-debug --gdb ./restart_all --max-allowed-packet=20M =head2 Stopping a group sandbox The natural way of stopping a group of sandboxes is to invoke the C script. This will work as expected most of the time. ./stop_all If you are dealing with a potentially unresponsive server (for example when testing alpha code), then you may use C, which will attempt a gentle stop first, and then kill the server brutally, if it does not respond after a predefined timeout of 10 seconds. ./send_kill_all =head2 Cleaning up a group sandbox To revert a group sandbox to its original state, the quickest way is to call C, which will invoke the C script in every depending single sandbox. ./clear_all In a replication sandbox, this command will also remove all replication settings. For this reason, C creates a dummy file called C, containing the date and time of the cleanup. This is a signal for C to initialize the slaves at the next occurrence. No need for the user to do anything special. The sandbox is self healing. =head2 Moving a group sandbox This recipe is the same for single and multiple sandboxes. Using the sbtool will move a sandbox in a clean and safe way. All the elements of the sandbox will be changed to adapt to the new location. sbtool -o move \ -s /path/to/source/sandbox \ -d /path/to/destination/directory =head2 Removing a group sandbox completely The sbtool can delete completely any sandbox, either single or multiple. sbtool -o delete \ -s /path/to/source/sandbox This operation will fail if the sandbox has been made permanent. (See next recipe). =head2 Making a group sandbox permanent A sandbox is designed to be easy to create and to throw away, because its primary purpose is testing. However, there are cases when you want to keep the contents around for a while, and you therefore want to make sure that the sandbox is not cleaned up or deleted by mistake. C achieves this goal by disabling the C script and the C script in all depending sandboxes. In this state, also the 'delete' operation fails (see previous recipe). sbtool -o preserve \ -s /path/to/source/sandbox When you need to get rid of the sandbox contents quickly, you can 'unpreserve' it, and the clear* scripts will be enabled again. sbtool -o unpreserve \ -s /path/to/source/sandbox =head1 Managing sandboxes in groups =head2 Using more than one SANDBOX_HOME The default $SANDBOX_HOME is $HOME/sandboxes, which is suitable for most purposes. If your $HOME is not fit for this task (e.g. if it is located in a NFS partition), you may set a different one on the command line or in your shell startup file. export SANDBOX_HOME=/my/alternative/directory make_sandbox 5.1.34 -- --check_port The above procedure is also useful when you, for any reasons, want a completely different set of sandboxes for a new batch of tests, and you want to be able to manage all of them at once. To avoid conflicts, you should always use the --check_port option. =head2 Stopping all sandboxes at once The $SANDBOX_HOME directory is the place containing all sandboxes, both single and multiple. This allows you to stop all of them at once with a single command. $SANDBOX_HOME/stop_all =head2 Starting all sandboxes at once Similarly to the previous recipe, you can start all sandboxes at once with a single command. $SANDBOX_HOME/start_all Notice that, if you created two or more sandboxes that use the same port, (create one with port X, stop it, create another with port X), there will be a conflict, and the second sandbox (and subsequent ones) won't start. =head2 Running the same query on all active sandboxes This is a quick way of getting a result from every sandbox under $SANDBOX_HOME. The query passed to C will be passed to every C or C scripts of the depending sandboxes. $SANDBOX_HOME/use_all 'select something_cool' If you want to run several queries from a script, use the C keyword: $SANDBOX_HOME/use_all 'source /full/path/to/script.sql' =head1 Testing with sandboxes =head2 Running the built-in test suite Download and expand the MySQL Sandbox package perl Makefile.PL make TEST_VERSION=/path/to/mysql/tarball make test # or TEST_VERSION=5.1.34 make test The TEST_VERSION environment variable contains a version or the path to a tarball used by the test suite. If no test version is provided, most of the tests are skipped. The test suite creates a private SANDBOX_HOME under ./t/test_sb. All the sandboxes needed for the test are executed there. If something goes wrong, that is the place to inspect for clues. IMPORTANT: When running test_sandbox, either standalone or within the test suite, it will stop all sandboxes inside $SANDBOX_HOME, to prevent conflicts with the sandboxes created during the tests. =head2 Creating and running your own tests Look at the ./t directory inside the MySQL Sandbox package (previous recipe). There are several .sb files, which are good examples of what you can do with the simple testing language. If this is not enough, you can use Perl itself. There are a few .sb.pl files, which are plugins for test_sandbox. Once you create your file, you can run it with test_sandbox --user_test=your_test.sb To use a Perl test, name the test with a .sb.pl extension. test_sandbox --user_test=your_test.sb.pl =head1 Remote Sandboxes =head2 Access sandboxes from other hosts By default, a MySQL sandbox instance can be accessed by localhost only. This access is regulated by an option, C<--remote_access>, which is set to '127.%', and it is used to create the default users. You can see the resulting instructions in the file 'grants.mysql' inside each sandbox. grant all on *.* to msandbox@'127.%' identified by 'msandbox'; grant all on *.* to msandbox@'localhost' identified by 'msandbox'; grant SELECT,EXECUTE on *.* to msandbox_ro@'127.%' identified by 'msandbox'; grant SELECT,EXECUTE on *.* to msandbox_ro@'localhost' identified by 'msandbox'; grant REPLICATION SLAVE on *.* to rsandbox@'127.%' identified by 'rsandbox'; If you want to access the sandbox remotely, you can change C<--remote_access> to include your specific subnet, or to open it completely --remote_access='192.168.1.%' --remote_access='%' Starting with MySQL::Sandbox 3.0.34, you can also define the bind address for your MySQL server. By default it is '127.0.0.1'. It will be changed to '0.0.0.0' if you choose a customized --remote_access. If you change both --remote_access and --bind_address, No adjustment will be made. =head2 Deploy MySQL sandboxes to many hosts MySQL Sandbox 3.0.32 and later include a script that lets you deploy a sandbox quickly to several hosts. $ deploy_to_remote_sandboxes.sh -h Deploy to remote sandboxes. Usage: deploy_to_remote_sandboxes.sh [options] -h => help -P port => MySQL port (15530) -d sandbox dir => sandbox directory name (remote_sb) -m version => MySQL version (5.5.30) -l list of nodes =>list of nodes where to deploy -t tarball => MySQL tarball to install remotely (none) This command takes the list of nodes and installs a MySQL sandbox in each one. You must have ssh access to the remote nodes, or this script won't work. =head1 COPYRIGHT Version 3.1 Copyright (C) 2006-2015 Giuseppe Maxia Home Page http://github.com/datacharmer =head1 LEGAL NOTICE Copyright 2006-2015 Giuseppe Maxia Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. MySQL-Sandbox-3.1.04/lib/MySQL/Sandbox/Scripts.pm000644 000765 000024 00000247523 12631363502 021353 0ustar00gmaxstaff000000 000000 package MySQL::Sandbox::Scripts; use strict; use warnings; use MySQL::Sandbox; require Exporter; our @ISA = qw/Exporter/; our @EXPORT_OK = qw( scripts_in_code get_readme_master_slave get_readme_circular get_readme_multiple get_readme_common get_readme_common_replication ); our @EXPORT = @EXPORT_OK; our $VERSION="3.1.04"; our @MANIFEST = ( 'clear.sh', 'my.sandbox.cnf', 'start.sh', 'status.sh', 'msb.sh', 'restart.sh', 'stop.sh', 'send_kill.sh', 'load_grants.sh', 'use.sh', 'mycli.sh', 'proxy_start.sh', 'my.sh', 'change_paths.sh', 'change_ports.sh', 'USING', 'README', 'connection.json', 'default_connection.json', 'grants.mysql', 'grants_5_7_6.mysql', 'json_in_db.sh', 'show_binlog.sh', 'show_relaylog.sh', 'add_option.sh', '# INSTALL FILES', 'sandbox_action.pl', 'test_replication.sh', ); #my $SBINSTR_SH_TEXT =<<'SBINSTR_SH_TEXT'; #if [ -f "$SBINSTR" ] #then # echo "[`basename $0`] - `date "+%Y-%m-%d %H:%M:%S"` - $@" >> $SBINSTR #fi #SBINSTR_SH_TEXT #sub sbinstr_sh_text { # return $MySQL::Sandbox::SBINSTR_SH_TEXT; #} sub manifest { return @MANIFEST; } my %parse_options_low_level_make_sandbox = ( upper_directory => { value => $ENV{'SANDBOX_HOME'} || $ENV{'HOME'}, parse => 'upper_directory=s', so => 10, help => [ "The directory that will contain the sandbox. (default: \$SANDBOX_HOME ($ENV{SANDBOX_HOME}))" ] }, sandbox_directory => { value => 'msb', parse => 'd|sandbox_directory=s', so => 20, export => 1, help => [ 'Where to install the sandbox, under upper-directory' ] }, sandbox_port => { value => 3310, parse => 'P|sandbox_port=i', export => 1, so => 30, help => [ 'The port number to use for the sandbox server.', '(Default: 3310)', ] }, check_port => { value => 0, parse => 'check_port', export => 1, so => 35, help => [ 'Check whether the provided port is free,', 'and determine the next available one if it is not.', '(Default: disabled)', ] }, no_check_port => { value => 0, parse => 'no_check_port', so => 36, help => [ 'Ignores requests of checking ports.', 'To be used by group sandbox scripts.', '(Default: disabled)', ] }, datadir_from => { value => 'script', parse => 'datadir_from=s' , so => 40, help => [ 'Where to get datadir files from. Available options are', 'archive will be taken from the archived data', ' provided with the package. They include', ' default username and passwords', ' ( DEPRECATED )', 'script the script mysql_install_db is called, with', ' default users, no passwords.', 'dir:name will be copied from an existing mysql directory', '(Default: script)', ] }, install_version => { value => '', parse => 'i|install_version=s', so => 50, help => [ 'Which version to install (3.23, 4.0, 4.1, 5.0 or 5.1) default: none' ] }, basedir => { value => '/usr/local/mysql', parse => 'b|basedir=s' , export => 1, so => 60, help => [ 'Base directory for MySQL (default: /usr/local/mysql)' ] }, tmpdir => { value => undef, parse => 'tmpdir=s' , export => 1, so => 65, help => [ 'Temporary directory for MySQL (default: Sandbox_directory/tmp)' ] }, my_file => { value => q{}, parse => 'm|my_file=s', so => 70, export => 1, help => [ 'which sample my-{small|large|huge}.cnf file should be used', 'for additional configuration', 'You may enter either the label (small|large|huge) or a full', 'file name. (default: none)', ] }, conf_file => { value => q{}, parse => 'f|conf_file=s', so => 80, help => [ 'Configuration file containing options like the ones', 'you can give on the command line (without dashes)', ] }, operating_system_user => { value => $ENV{'USER'}, parse => 'U|operating_system_user=s', so => 90, help => [ 'Operating system user (for mysql installation)', "default: \$USER ($ENV{USER})", ] }, db_user => { value => $MySQL::Sandbox::default_users{'db_user'}, parse => 'u|db_user=s' , so => 100, export => 1, help => [ 'user for global access to mysql (Default: ' . $MySQL::Sandbox::default_users{'db_user'} . ')' ] }, remote_access => { value => $MySQL::Sandbox::default_users{'remote_access'}, parse => 'remote_access=s' , so => 101, export => 1, help => [ 'network access for mysql users (Default: ' . $MySQL::Sandbox::default_users{'remote_access'} . ')' ] }, bind_address => { value => '127.0.0.1', parse => 'bind_address=s' , so => 102, export => 1, help => [ 'Bind address for mysql server (Default: 127.0.0.1' ] }, ro_user => { value => $MySQL::Sandbox::default_users{'ro_user'}, parse => 'ro_user=s' , so => 103, export => 1, help => [ 'user for read-only access to mysql (Default: ' . $MySQL::Sandbox::default_users{'ro_user'} . ')' ] }, rw_user => { value => $MySQL::Sandbox::default_users{'rw_user'}, parse => 'rw_user=s' , so => 105, export => 1, help => [ 'user for read-write access to mysql (Default: ' . $MySQL::Sandbox::default_users{'rw_user'} . ')' ] }, repl_user => { value => $MySQL::Sandbox::default_users{'repl_user'}, parse => 'repl_user=s' , so => 106, export => 1, help => [ 'user for replication access to mysql (Default: ' . $MySQL::Sandbox::default_users{'repl_user'} . ')' ] }, db_password => { value => $MySQL::Sandbox::default_users{'db_password'}, parse => 'p|db_password=s' , so => 110, export => 1, help => [ 'password for global access to mysql (Default: ' . $MySQL::Sandbox::default_users{'db_password'} . ')' ] }, repl_password => { value => $MySQL::Sandbox::default_users{'repl_password'}, parse => 'repl_password=s' , so => 112, export => 1, help => [ 'password for replication access to mysql (Default: ' . $MySQL::Sandbox::default_users{'repl_password'} . ')' ] }, my_clause => { value => '', parse => 'c|my_clause=s@', so => 120, export => 1, help => [ 'option to be inserted in a my.cnf file', 'it may be used several times', ] }, master => { value => 0, parse => 'master', so => 124, export => 1, help => [ 'configures the server as a master (enables binlog and sets server ID)' ] }, slaveof => { value => undef, parse => 'slaveof=s', so => 125, export => 1, help => [ 'Configures the server as a slave of another sandbox ', 'Requires options for CHANGE MASTER TO, (at least master_port).', 'If options other than master_port are provided, they will override the defaults', 'and it will be possible to set a slave for a non-sandbox server' ] }, high_performance => { value => 0, parse => 'high_performance', so => 126, export => 1, help => [ 'configures the server for high performance' ] }, prompt_prefix => { value => 'mysql', parse => 'prompt_prefix=s', so => 130, export => 1, help => [ 'prefix to use in CLI prompt (default: mysql)', ] }, prompt_body => { value => q/ [\h] {\u} (\d) > /, parse => 'prompt_body=s', so => 135, export => 1, help => [ 'options to use in CLI prompt (default: [\h] {\u} (\d) > )', ] }, force => { value => 0, parse => 'force', so => 140, export => 1, help => [ 'Use this option if you want to overwrite existing directories', 'and files during the installation. (Default: disabled)', ] }, no_ver_after_name => { value => 0, parse => 'no_ver_after_name', so => 150, help => [ 'Do not add version number after sandbox directory name (default: disabled)' ] }, verbose => { value => 0, parse => 'v|verbose', so => 160, export => 1, help => [ 'Use this option to see installation progress (default: disabled)' ] }, load_grants => { value => 0, parse => 'load_grants', so => 170, export => 1, help => [ 'Loads the predefined grants from a SQL file.', 'Useful when installing from script.', '(default: disabled)' ] }, no_load_grants => { value => 0, parse => 'no_load_grants', so => 175, help => [ 'Does not loads the predefined grants from a SQL file.', '(default: disabled)' ] }, no_run => { value => 0, parse => 'no_run', so => 176, help => [ 'Stops the server if started with "load_grants".', '(default: disabled)' ] }, # # This option requires rewriting several installation steps # For now ( April 29, 2014) we are only supporting MySQL 5.7.4 without random password. # More support will come later # # random_password => { # value => 0, # parse => 'random_password', # so => 195, # help => [ # 'Enables random password generation with MySQL 5.7.4+' # ] # }, interactive => { value => 0, parse => 't|interactive', so => 180, help => [ 'Use this option to be guided through the installation process (default: disabled)' ] }, more_options => { value => q{}, parse => undef, so => 20}, help => { value => q{}, parse => 'help', so => 25}, no_confirm => { value => 0, parse => 'no_confirm', export => 1, so => 180, help => [ 'suppress the confirmation request from user', ], }, no_show => { value => 0, parse => 'no_show', so => 190, help => [ 'does not show options or ask confirmation to the user', ], }, keep_uuid => { value => $ENV{KEEP_UUID} || $ENV{keep_uuid} || 0, parse => 'keep_uuid', so => 195, help => [ 'does not modify server UUID in MySQL 5.6+', ], }, history_dir => { value => $ENV{HISTORY_DIR} || $ENV{HISTORYDIR} || '', parse => 'history_dir=s', so => 197, help => [ 'Sets the history directory for mysql client to a given path', ], }, ); my %parse_options_replication = ( upper_directory => { value => $ENV{'SANDBOX_HOME'} || $ENV{'HOME'}, parse => 'upper_directory=s', so => 10, help => [ "The directory containing the sandbox. (default: \$SANDBOX_HOME ($ENV{SANDBOX_HOME}))" ] }, replication_directory => { value => undef, parse => 'r|replication_directory=s', so => 20, help => [ 'Where to install the sandbox replication system, under upper-directory', 'default: (rsandbox)' ] }, server_version => { value => undef, parse => 'server_version=s', so => 30, help => [ 'which version to install' ] }, sandbox_base_port => { value => undef, parse => 'sandbox_base_port=i', so => 40, help => [ 'The port number to use for the sandbox replication system.', '(Default: 11000 + version )', ] }, check_base_port => { value => undef, parse => 'check_base_port', so => 45, help => [ 'Check that the ports are available ', '(Default: disabled )', ] }, how_many_slaves => { value => 2, parse => 'how_many_nodes|how_many_slaves=i', so => 50, help => [ 'The number of slaves to create.', '(Default: 2)', ] }, topology => { value => 'standard', parse => 't|topology=s', so => 60, help => [ 'Sets a replication topology.', 'Available: {standard|circular} (default: standard)' ] }, circular => { value => 0, parse => 'circular=i', so => 70, help => [ 'Sets circular replication with N nodes.', '(default: 0)' ] }, master_master => { value => 0, parse => 'master_master', so => 80, help => [ 'set exactly two nodes in circular replication' ] }, repl_user => { value => $MySQL::Sandbox::default_users{'repl_user'}, parse => 'repl_user=s', so => 90, help => [ 'user with replication slave privileges.', '(default: '. $MySQL::Sandbox::default_users{'repl_user'} . ')' ] }, repl_password => { value => $MySQL::Sandbox::default_users{'repl_password'}, parse => 'repl_password=s', so => 100, help => [ 'password for user with replication slave privileges.', '(default: '. $MySQL::Sandbox::default_users{'repl_password'} . ')' ] }, remote_access => { value => $MySQL::Sandbox::default_users{'remote_access'}, parse => 'remote_access=s' , so => 110, help => [ 'network access for mysql users (Default: ' . $MySQL::Sandbox::default_users{'remote_access'} . ')' ] }, master_options => { value => '', parse => 'master_options=s' , so => 120, help => [ 'Options passed to the master (Default: "" )' ] }, slave_options => { value => '', parse => 'slave_options=s' , so => 120, help => [ 'Options passed to each slave (Default: "" )' ] }, node_options => { value => '', parse => 'node_options=s' , so => 130, help => [ 'Options passed to each node (Default: "" )' ] }, one_slave_options => { value => '', parse => 'one_slave_options=s@' , so => 130, help => [ 'Options passed to a specific slave with the format "N:options"', '(Default: "" )' ] }, interactive => { value => 0, parse => 'interactive', so => 210, help => [ 'Use this option to ask interactive user ', 'confirmation for each node (default: disabled)' ] }, verbose => { value => 0, parse => 'v|verbose', so => 220, help => [ 'Use this option to see installation progress (default: disabled)' ] }, help => { value => 0, parse => 'help', so => 230, help => [ 'show this help (default: disabled)' ] }, ); my %parse_options_many = ( upper_directory => { value => $ENV{'SANDBOX_HOME'} || $ENV{'HOME'}, parse => 'upper_directory=s', so => 10, help => [ "The directory containing the sandbox. (default: \$SANDBOX_HOME ($ENV{SANDBOX_HOME}))" ] }, group_directory => { value => undef, parse => 'r|group_directory=s', so => 20, help => [ 'Where to install the sandbox group, under home-directory', 'default: (multi_msb)' ] }, server_version => { value => undef, parse => 'server_version=s', so => 30, help => [ 'which version to install' ] }, sandbox_base_port => { value => undef, parse => 'sandbox_base_port=i', so => 40, help => [ 'The port number to use for the sandbox multiple system.', '(Default: 7000 + version )', ] }, check_base_port => { value => undef, parse => 'check_base_port', so => 45, help => [ 'Check that the ports are available ', '(Default: disabled )', ] }, how_many_nodes => { value => 3, parse => 'how_many_nodes=i', so => 50, help => [ 'The number of nodes to create.', '(Default: 3)', ] }, master_master => { value => 0, parse => 'master_master', so => 60, help => [ 'set exactly two nodes in circular replication' ] }, circular => { value => 0, parse => 'circular', so => 70, help => [ 'set the nodes in circular replication' ] }, repl_user => { value => $MySQL::Sandbox::default_users{'repl_user'}, parse => 'repl_user=s', so => 80, help => [ 'user with replication slave privileges.', '(default: '. $MySQL::Sandbox::default_users{'repl_user'} . ')' ] }, repl_password => { value => $MySQL::Sandbox::default_users{'repl_password'}, parse => 'repl_password=s', so => 90, help => [ 'password for user with replication slave privileges.', '(default: '. $MySQL::Sandbox::default_users{'repl_password'} . ')' ] }, remote_access => { value => $MySQL::Sandbox::default_users{'remote_access'}, parse => 'remote_access=s' , so => 100, help => [ 'network access for mysql users (Default: ' . $MySQL::Sandbox::default_users{'remote_access'} . ')' ] }, node_options => { value => '', parse => 'node_options=s' , so => 130, help => [ 'Options passed to each node (Default: "" )' ] }, one_node_options => { value => '', parse => 'one_node_options=s@' , so => 140, help => [ 'Options passed to a specific node with the format "N:options"', '(Default: "" )' ] }, interactive => { value => 0, parse => 'interactive', so => 210, help => [ 'Use this option to ask interactive user ', 'confirmation for each node (default: disabled)' ] }, verbose => { value => 0, parse => 'v|verbose', so => 220, help => [ 'Use this option to see installation progress (default: disabled)' ] }, help => { value => 0, parse => 'help', so => 230, help => [ 'show this help (default: disabled)' ] }, ); my %parse_options_custom_many = ( upper_directory => { value => $ENV{'SANDBOX_HOME'} || $ENV{'HOME'}, parse => 'upper_directory=s', so => 10, help => [ "The directory containing the sandbox. (default: \$SANDBOX_HOME ($ENV{SANDBOX_HOME}))" ] }, group_directory => { value => undef, parse => 'r|group_directory=s', so => 20, help => [ 'Where to install the sandbox group, under home-directory', 'default: (multi_msb)' ] }, server_version => { value => undef, parse => 'server_version=s', so => 30, help => [ 'which version to install' ] }, sandbox_base_port => { value => undef, parse => 'sandbox_base_port=i', so => 40, help => [ 'The port number to use for the sandbox custom system.', '(Default: 5000 + version )', ] }, check_base_port => { value => undef, parse => 'check_base_port', so => 45, help => [ 'Check that the ports are available ', '(Default: disabled )', ] }, node_options => { value => '', parse => 'node_options=s' , so => 130, help => [ 'Options passed to each node (Default: "" )' ] }, one_node_options => { value => '', parse => 'one_node_options=s@' , so => 140, help => [ 'Options passed to a specific node with the format "N:options"', '(Default: "" )' ] }, interactive => { value => 0, parse => 'interactive', so => 210, help => [ 'Use this option to ask interactive user ', 'confirmation for each node (default: disabled)' ] }, verbose => { value => 0, parse => 'v|verbose', so => 220, help => [ 'Use this option to see installation progress (default: disabled)' ] }, help => { value => 0, parse => 'help', so => 230, help => [ 'show this help (default: disabled)' ] }, ); our %sbtool_supported_operations = ( ports => 'lists ports used by the Sandbox', range => 'finds N consecutive ports not yet used by the Sandbox', info => 'returns configuration options from a Sandbox', tree => 'creates a replication tree', copy => 'copies data from one Sandbox to another', move => 'moves a Sandbox to a different location', port => 'Changes a Sandbox port', delete => 'removes a sandbox completely', preserve => 'makes a sandbox permanent', unpreserve => 'makes a sandbox NOT permanent', plugin => 'adds plugin support to a sandbox (innodb,semisynch)', ); our %sbtool_supported_formats = ( text => 'plain text dump of requested information', perl => 'fully structured information in Perl code', ); #our %sbtool_supported_plugins = ( # innodb => 'innodb plugin (5.1)', # semisync => 'semi synchrounus replication (5.5)', # gearman => 'Gearman UDF', #); my %parse_options_sbtool = ( operation => { so => 10, parse => 'o|operation=s', value => undef, accepted => \%sbtool_supported_operations, help => 'what task to perform', }, source_dir => { so => 20, parse => 's|source_dir=s', value => undef, help => 'source directory for move, copy, delete', }, dest_dir => { so => 30, parse => 'd|dest_dir=s', value => undef, help => 'destination directory for move,copy', }, new_port => { so => 40, parse => 'n|new_port=s', value => undef, help => 'new port while moving a sandbox', }, only_used => { so => 50, parse => 'u|only_used', value => 0, help => 'for "ports" operation, shows only the used ones', }, min_range => { so => 60, parse => 'i|min_range=i', value => 5000, help => 'minimum port when searching for available ranges', }, max_range => { so => 70, parse => 'x|max_range=i', value => 64000, help => 'maximum port when searching for available ranges', }, range_size => { so => 80, parse => 'z|range_size=i', value => 10, help => 'size of range when searching for available port range', }, format => { so => 90, parse => 'f|format=s', value => 'text', accepted => \%sbtool_supported_formats, help => 'format for "ports" and "info"', }, search_path => { so => 100, parse => 'p|search_path=s', value => $ENV{SANDBOX_HOME}, help => 'search path for ports and info', }, all_info => { so => 110, parse => 'a|all_info', value => 0, help => 'print more info for "ports" operation' }, master_node => { so => 115, parse => 'master_node=i', value => '1', help => 'which node should be master (default: 1)', }, tree_nodes => { so => 120, parse => 'tree_nodes=s', value => '', help => 'description of the tree (x-x x x-x x|x x x|x x)', }, mid_nodes => { so => 130, parse => 'mid_nodes=s', value => '', help => 'description of the middle nodes (x x x)', }, leaf_nodes => { so => 140, parse => 'leaf_nodes=s', value => '', help => 'description of the leaf nodes (x x|x x x|x x)', }, tree_dir => { so => 150, parse => 'tree_dir=s', value => '', help => 'which directory contains the tree nodes', }, verbose => { so => 160, parse => 'v|verbose', value => 0, help => 'prints more info on some operations' }, plugin => { so => 170, parse => 'plugin=s', value => undef, help => 'install given plugin in sandbox', }, plugin_file => { so => 180, parse => 'plugin_file=s', value => undef, help => 'plugin configuration file to use instead of default plugin.conf', }, help => { so => 999, parse => 'h|help', value => undef, help => 'this screen', }, ); # --- START SCRIPTS IN CODE --- my %scripts_in_code = ( 'msb.sh' => <<'MSB_SCRIPT', #!_BINBASH_ __LICENSE__ ACCEPTED="{start|stop|restart|clear|send_kill|status}" if [ "$1" == "" ] then echo "argument required $ACCEPTED" exit 1 fi SBDIR="_HOME_DIR_/_SANDBOXDIR_" CMD=$1 shift if [ -x "$SBDIR/$CMD" ] then $SBDIR/$CMD "$@" else echo "unrecognized command '$CMD'" echo "accepted: $ACCEPTED" exit 1 fi #case $CMD in # start) $SBDIR/start "$@" ;; # restart) $SBDIR/restart "$@" ;; # stop) $SBDIR/stop "$@" ;; # clear) $SBDIR/clear "$@" ;; # send_kill) $SBDIR/send_kill "$@" ;; # status) $SBDIR/status "$@" ;; # *) # echo "unrecognized command '$CMD'" # echo "accepted: $ACCEPTED" # exit 1 # ;; #esac MSB_SCRIPT 'start.sh' => <<'START_SCRIPT', #!_BINBASH_ __LICENSE__ BASEDIR='_BASEDIR_' export LD_LIBRARY_PATH=$BASEDIR/lib:$BASEDIR/lib/mysql:$LD_LIBRARY_PATH export DYLD_LIBRARY_PATH=$BASEDIR_/lib:$BASEDIR/lib/mysql:$DYLD_LIBRARY_PATH MYSQLD_SAFE="$BASEDIR/bin/_MYSQLDSAFE_" SBDIR="_HOME_DIR_/_SANDBOXDIR_" PIDFILE="$SBDIR/data/mysql_sandbox_SERVERPORT_.pid" __SBINSTR_SH__ if [ ! -f $MYSQLD_SAFE ] then echo "mysqld_safe not found in $BASEDIR/bin/" exit 1 fi MYSQLD_SAFE_OK=`sh -n $MYSQLD_SAFE 2>&1` if [ "$MYSQLD_SAFE_OK" == "" ] then if [ "$SBDEBUG" == "2" ] then echo "$MYSQLD_SAFE OK" fi else echo "$MYSQLD_SAFE has errors" echo "((( $MYSQLD_SAFE_OK )))" exit 1 fi function is_running { if [ -f $PIDFILE ] then MYPID=$(cat $PIDFILE) ps -p $MYPID | grep $MYPID fi } TIMEOUT=180 if [ -n "$(is_running)" ] then echo "sandbox server already started (found pid file $PIDFILE)" else if [ -f $PIDFILE ] then # Server is not running. Removing stale pid-file rm -f $PIDFILE fi CURDIR=`pwd` cd $BASEDIR if [ "$SBDEBUG" = "" ] then $MYSQLD_SAFE --defaults-file=$SBDIR/my.sandbox.cnf $@ > /dev/null 2>&1 & else $MYSQLD_SAFE --defaults-file=$SBDIR/my.sandbox.cnf $@ > "$SBDIR/start.log" 2>&1 & fi cd $CURDIR ATTEMPTS=1 while [ ! -f $PIDFILE ] do ATTEMPTS=$(( $ATTEMPTS + 1 )) echo -n "." if [ $ATTEMPTS = $TIMEOUT ] then break fi sleep 1 done fi if [ -f $PIDFILE ] then echo " sandbox server started" #if [ -f $SBDIR/needs_reload ] #then # if [ -f $SBDIR/rescue_mysql_dump.sql ] # then # $SBDIR/use mysql < $SBDIR/rescue_mysql_dump.sql # fi # rm $SBDIR/needs_reload #fi else echo " sandbox server not started yet" exit 1 fi START_SCRIPT 'status.sh' => <<'STATUS_SCRIPT', #!_BINBASH_ __LICENSE__ SBDIR="_HOME_DIR_/_SANDBOXDIR_" PIDFILE="$SBDIR/data/mysql_sandbox_SERVERPORT_.pid" __SBINSTR_SH__ node_status=off exit_code=1 if [ -f $PIDFILE ] then MYPID=$(cat $PIDFILE) running=$(ps -p $MYPID | grep $MYPID) if [ -n "$running" ] then node_status=on exit_code=0 fi fi echo "_SANDBOXDIR_ $node_status" exit $exit_code STATUS_SCRIPT 'restart.sh' => <<'RESTART_SCRIPT', #!_BINBASH_ __LICENSE__ __SBINSTR_SH__ SBDIR="_HOME_DIR_/_SANDBOXDIR_" $SBDIR/stop $SBDIR/start $@ RESTART_SCRIPT 'stop.sh' => <<'STOP_SCRIPT', #!_BINBASH_ __LICENSE__ SBDIR="_HOME_DIR_/_SANDBOXDIR_" BASEDIR=_BASEDIR_ export LD_LIBRARY_PATH=$BASEDIR/lib:$BASEDIR/lib/mysql:$LD_LIBRARY_PATH export DYLD_LIBRARY_PATH=$BASEDIR/lib:$BASEDIR/lib/mysql:$DYLD_LIBRARY_PATH MYSQL_ADMIN="$BASEDIR/bin/mysqladmin" PIDFILE="$SBDIR/data/mysql_sandbox_SERVERPORT_.pid" __SBINSTR_SH__ function is_running { if [ -f $PIDFILE ] then MYPID=$(cat $PIDFILE) ps -p $MYPID | grep $MYPID fi } if [ -n "$(is_running)" ] then if [ -f $SBDIR/data/master.info ] then echo "stop slave" | $SBDIR/use -u root fi # echo "$MYSQL_ADMIN --defaults-file=$SBDIR/my.sandbox.cnf $MYCLIENT_OPTIONS shutdown" $MYSQL_ADMIN --defaults-file=$SBDIR/my.sandbox.cnf $MYCLIENT_OPTIONS shutdown sleep 1 else if [ -f $PIDFILE ] then rm -f $PIDFILE fi fi if [ -n "$(is_running)" ] then # use the send_kill script if the server is not responsive $SBDIR/send_kill fi STOP_SCRIPT 'send_kill.sh' => <<'KILL_SCRIPT', #!_BINBASH_ __LICENSE__ SBDIR="_HOME_DIR_/_SANDBOXDIR_" PIDFILE="$SBDIR/data/mysql_sandbox_SERVERPORT_.pid" TIMEOUT=30 __SBINSTR_SH__ function is_running { if [ -f $PIDFILE ] then MYPID=$(cat $PIDFILE) ps -p $MYPID | grep $MYPID fi } if [ -n "$(is_running)" ] then MYPID=`cat $PIDFILE` echo "Attempting normal termination --- kill -15 $MYPID" kill -15 $MYPID # give it a chance to exit peacefully ATTEMPTS=1 while [ -f $PIDFILE ] do ATTEMPTS=$(( $ATTEMPTS + 1 )) if [ $ATTEMPTS = $TIMEOUT ] then break fi sleep 1 done if [ -f $PIDFILE ] then echo "SERVER UNRESPONSIVE --- kill -9 $MYPID" kill -9 $MYPID rm -f $PIDFILE fi else # server not running - removing stale pid-file if [ -f $PIDFILE ] then rm -f $PIDFILE fi fi KILL_SCRIPT 'json_in_db.sh' => <<'JSON_IN_DB_SCRIPT', #!_BINBASH_ __LICENSE__ SBDIR="_HOME_DIR_/_SANDBOXDIR_" cd $SBDIR ./use -e 'drop table if exists test.connection_json' ./use -e 'create table test.connection_json(t longtext)' ./use -e '/*!50708 alter table test.connection_json modify t json */' #./use -e "insert into test.connection_json values (load_file('$SBDIR/connection.json'))" ./use -e "insert into test.connection_json values ( /*!50708 convert( */ load_file('$SBDIR/connection.json') /*!50708 using UTF8 ) */ )" if [ "$?" != "0" ] then echo "error loading connection.json to the database" exit 1 fi echo "connection.json saved to test.connection_json" JSON_IN_DB_SCRIPT 'use.sh' => <<'USE_SCRIPT', #!_BINBASH_ __LICENSE__ export LD_LIBRARY_PATH=_BASEDIR_/lib:_BASEDIR_/lib/mysql:$LD_LIBRARY_PATH export DYLD_LIBRARY_PATH=_BASEDIR_/lib:_BASEDIR_/lib/mysql:$DYLD_LIBRARY_PATH SBDIR="_HOME_DIR_/_SANDBOXDIR_" BASEDIR=_BASEDIR_ [ -z "$MYSQL_EDITOR" ] && MYSQL_EDITOR="$BASEDIR/bin/mysql" HISTDIR=_HISTORY_DIR_ [ -z "$HISTDIR" ] && HISTDIR=$SBDIR export MYSQL_HISTFILE="$HISTDIR/.mysql_history" PIDFILE="$SBDIR/data/mysql_sandbox_SERVERPORT_.pid" __SBINSTR_SH__ if [ -f $PIDFILE ] then $MYSQL_EDITOR --defaults-file=$SBDIR/my.sandbox.cnf $MYCLIENT_OPTIONS "$@" #else # echo "PID file $PIDFILE not found " fi USE_SCRIPT 'mycli.sh' => <<'MYCLI_SCRIPT', #!_BINBASH_ __LICENSE__ export LD_LIBRARY_PATH=_BASEDIR_/lib:_BASEDIR_/lib/mysql:$LD_LIBRARY_PATH export DYLD_LIBRARY_PATH=_BASEDIR_/lib:_BASEDIR_/lib/mysql:$DYLD_LIBRARY_PATH SBDIR="_HOME_DIR_/_SANDBOXDIR_" BASEDIR=_BASEDIR_ mycli --user=_DBUSER_ \ --pass=_DBPASSWORD_ \ --port=_SERVERPORT_ \ --socket=_GLOBALTMPDIR_/mysql_sandbox_SERVERPORT_.sock \ --_MYSQL_PROMPT_ "$@" MYCLI_SCRIPT 'clear.sh' => <<'CLEAR_SCRIPT', #!_BINBASH_ __LICENSE__ SBDIR="_HOME_DIR_/_SANDBOXDIR_" cd $SBDIR PIDFILE="$SBDIR/data/mysql_sandbox_SERVERPORT_.pid" __SBINSTR_SH__ # # attempt to drop databases gracefully # function is_running { if [ -f $PIDFILE ] then MYPID=$(cat $PIDFILE) ps -p $MYPID | grep $MYPID fi } if [ -n "$(is_running)" ] then for D in `echo "show databases " | ./use -B -N | grep -v "^mysql$" | grep -iv "^information_schema$" | grep -iv "^performance_schema" | grep -ivw "^sys"` do echo "set sql_mode=ansi_quotes;drop database \"$D\"" | ./use done VERSION=`./use -N -B -e 'select left(version(),3)'` #if [ `perl -le 'print $ARGV[0] ge "5.0" ? "1" : "0" ' "$VERSION"` = "1" ] #then # ./use -e "truncate mysql.proc" # ./use -e "truncate mysql.func" #fi is_slave=$(ls data | grep relay) if [ -n "$is_slave" ] then ./use -e "stop slave; reset slave;" fi if [ `perl -le 'print $ARGV[0] ge "5.1" ? "1" : "0" ' "$VERSION"` = "1" ] then for T in general_log slow_log plugin do exists_table=$(./use -e "show tables from mysql like '$T'") if [ -n "$exists_table" ] then ./use -e "truncate mysql.$T" fi done fi fi is_master=$(ls data | grep 'mysql-bin') if [ -n "$is_master" ] then ./use -e 'reset master' fi ./stop #./send_kill rm -f data/`hostname`* rm -f data/log.0* rm -f data/*.log rm -f data/falcon* rm -f data/mysql-bin* rm -f data/*relay-bin* rm -f data/ib_* rm -f data/*.info rm -f data/*.err rm -f data/*.err-old #if [ `perl -le 'print $ARGV[0] ge "5.6" ? "1" : "0" ' "$VERSION"` = "1" ] #then # rm -f data/mysql/slave_* # rm -f data/mysql/innodb_* # touch needs_reload #fi # rm -rf data/test/* # # remove all databases if any # for D in `ls -d data/*/ | grep -w -v mysql | grep -iv performance_schema | grep -ivw sys` do rm -rf $D done mkdir data/test CLEAR_SCRIPT 'my.sandbox.cnf' => <<'MY_SANDBOX_SCRIPT', __LICENSE__ [mysql] _MYSQL_PROMPT_ # [client] user = _DBUSER_ password = _DBPASSWORD_ port = _SERVERPORT_ socket = _GLOBALTMPDIR_/mysql_sandbox_SERVERPORT_.sock [mysqld] user = _OSUSER_ port = _SERVERPORT_ socket = _GLOBALTMPDIR_/mysql_sandbox_SERVERPORT_.sock basedir = _BASEDIR_ datadir = _HOME_DIR_/_SANDBOXDIR_/data tmpdir = _TMPDIR_ lower_case_table_names = _LOWER_CASE_TABLE_NAMES_ pid-file = _HOME_DIR_/_SANDBOXDIR_/data/mysql_sandbox_SERVERPORT_.pid bind-address = _BIND_ADDRESS_ # _SLOW_QUERY_LOG_ # _GENERAL_LOG_ _MORE_OPTIONS_ MY_SANDBOX_SCRIPT 'USING' => < MySQL::Sandbox::credits() . "\n" . < <<'GRANTS_MYSQL', use mysql; set password=password('_DBPASSWORD_'); grant all on *.* to _DBUSER_@'_REMOTE_ACCESS_' identified by '_DBPASSWORD_'; grant all on *.* to _DBUSER_@'localhost' identified by '_DBPASSWORD_'; grant SELECT,INSERT,UPDATE,DELETE,CREATE,DROP,INDEX,ALTER, SHOW DATABASES,CREATE TEMPORARY TABLES,LOCK TABLES, EXECUTE on *.* to _DBUSERRW_@'localhost' identified by '_DBPASSWORD_'; grant SELECT,INSERT,UPDATE,DELETE,CREATE,DROP,INDEX,ALTER, SHOW DATABASES,CREATE TEMPORARY TABLES,LOCK TABLES, EXECUTE on *.* to _DBUSERRW_@'_REMOTE_ACCESS_' identified by '_DBPASSWORD_'; grant SELECT,EXECUTE on *.* to _DBUSERRO_@'_REMOTE_ACCESS_' identified by '_DBPASSWORD_'; grant SELECT,EXECUTE on *.* to _DBUSERRO_@'localhost' identified by '_DBPASSWORD_'; grant REPLICATION SLAVE on *.* to _DBUSERREPL_@'_REMOTE_ACCESS_' identified by '_DB_REPL_PASSWORD_'; delete from user where password=''; delete from db where user=''; flush privileges; create database if not exists test; GRANTS_MYSQL 'grants_5_7_6.mysql' => <<'GRANTS_MYSQL_5_7_6', use mysql; set password='_DBPASSWORD_'; -- delete from tables_priv; -- delete from columns_priv; -- delete from db; delete from user where user not in ('root', 'mysql.sys'); flush privileges; create user _DBUSER_@'_REMOTE_ACCESS_' identified by '_DBPASSWORD_'; grant all on *.* to _DBUSER_@'_REMOTE_ACCESS_' ; create user _DBUSER_@'localhost' identified by '_DBPASSWORD_'; grant all on *.* to _DBUSER_@'localhost'; create user _DBUSERRW_@'localhost' identified by '_DBPASSWORD_'; grant SELECT,INSERT,UPDATE,DELETE,CREATE,DROP,INDEX,ALTER, SHOW DATABASES,CREATE TEMPORARY TABLES,LOCK TABLES, EXECUTE on *.* to _DBUSERRW_@'localhost'; create user _DBUSERRW_@'_REMOTE_ACCESS_' identified by '_DBPASSWORD_'; grant SELECT,INSERT,UPDATE,DELETE,CREATE,DROP,INDEX,ALTER, SHOW DATABASES,CREATE TEMPORARY TABLES,LOCK TABLES, EXECUTE on *.* to _DBUSERRW_@'_REMOTE_ACCESS_'; create user _DBUSERRO_@'_REMOTE_ACCESS_' identified by '_DBPASSWORD_'; create user _DBUSERRO_@'localhost' identified by '_DBPASSWORD_'; create user _DBUSERREPL_@'_REMOTE_ACCESS_' identified by '_DB_REPL_PASSWORD_'; grant SELECT,EXECUTE on *.* to _DBUSERRO_@'_REMOTE_ACCESS_'; grant SELECT,EXECUTE on *.* to _DBUSERRO_@'localhost'; grant REPLICATION SLAVE on *.* to _DBUSERREPL_@'_REMOTE_ACCESS_'; create schema if not exists test; GRANTS_MYSQL_5_7_6 'load_grants.sh' => << 'LOAD_GRANTS_SCRIPT', #!_BINBASH_ __LICENSE__ SBDIR=_HOME_DIR_/_SANDBOXDIR_ BASEDIR='_BASEDIR_' export LD_LIBRARY_PATH=$BASEDIR/lib:$BASEDIR/lib/mysql:$LD_LIBRARY_PATH export DYLD_LIBRARY_PATH=$BASEDIR_/lib:$BASEDIR/lib/mysql:$DYLD_LIBRARY_PATH MYSQL="$BASEDIR/bin/mysql --no-defaults --socket=_GLOBALTMPDIR_/mysql_sandbox_SERVERPORT_.sock --port=_SERVERPORT_" # START UGLY WORKAROUND for grants syntax changes in 5.7.6 VERSION=`$MYSQL -u root -BN -e 'select version()' | perl -ne 'print $1 if /(\d+\.\d+\.\d+)/'` MAJOR=$(echo $VERSION | tr '.' ' ' | awk '{print $1}') MINOR=$(echo $VERSION | tr '.' ' ' | awk '{print $2}') REV=$(echo $VERSION | tr '.' ' ' | awk '{print $3}') if [ "$MAJOR" == "5" -a "$MINOR" == "7" -a "$REV" == "8" ] then # workaround for Bug#77732. echo "grant SELECT on performance_schema.global_variables to _DBUSERREPL_@'_REMOTE_ACCESS_';" >> $SBDIR/grants_5_7_6.mysql echo "grant SELECT on performance_schema.session_variables to _DBUSERREPL_@'_REMOTE_ACCESS_';" >> $SBDIR/grants_5_7_6.mysql fi if [ "$MAJOR" == "5" -a "$MINOR" == "7" -a $REV -gt 5 ] then cp $SBDIR/grants_5_7_6.mysql $SBDIR/grants.mysql fi # END UGLY WORKAROUND VERBOSE_SQL='' [ -n "$SBDEBUG" ] && VERBOSE_SQL=-v $MYSQL -u root $VERBOSE_SQL < $SBDIR/grants.mysql # echo "source $SBDIR/grants.mysql" | $SBDIR/use -u root --password= # $SBDIR/my sqldump _EVENTS_OPTIONS_ mysql > $SBDIR/rescue_mysql_dump.sql LOAD_GRANTS_SCRIPT 'default_connection.json' => <<'END_DEFAULT_CONNECTION_JSON', { "host": "127.0.0.1", "port": "_SERVERPORT_", "socket": "_GLOBALTMPDIR_/mysql_sandbox_SERVERPORT_.sock", "username": "_DBUSER_@_REMOTE_ACCESS_", "password": "_DBPASSWORD_" } END_DEFAULT_CONNECTION_JSON 'connection.json' => <<'END_CONNECTION_JSON', { "origin": { "mysql_sandbox_version" : "_MSB_VERSION_", "mysql_version": "_INSTALL_VERSION_", "binaries": "_BASEDIR_" }, "connection": { "host": "127.0.0.1", "port": "_SERVERPORT_", "socket": "_GLOBALTMPDIR_/mysql_sandbox_SERVERPORT_.sock", "bind_address": "_BIND_ADDRESS_" }, "users": { "admin": { "username": "root@localhost", "password": "_DBPASSWORD_", "privileges": "all, with grant option" }, "all_privileges": { "username": "_DBUSER_@_REMOTE_ACCESS_", "password": "_DBPASSWORD_", "privileges": "all, no grant option" }, "read_write": { "username": "_DBUSERRW_@_REMOTE_ACCESS_", "password": "_DBPASSWORD_", "privileges": "SELECT,INSERT,UPDATE,DELETE,CREATE,DROP,INDEX,ALTER,SHOW DATABASES,CREATE TEMPORARY TABLES,LOCK TABLES, EXECUTE" }, "read_only": { "username": "_DBUSERRO_@_REMOTE_ACCESS_", "password": "_DBPASSWORD_", "privileges": "SELECT,EXECUTE" }, "replication": { "username": "_DBUSERREPL_@_REMOTE_ACCESS_", "password": "_DB_REPL_PASSWORD_", "privileges": "REPLICATION SLAVE" } }, "samples": { "php": { "mysqli" : "$mysqli = new mysqli('127.0.0.1', '_DBUSER_', '_DBPASSWORD_', 'test', '_SERVERPORT_');", "pdo" : "$dbh = new PDO('mysql:host=127.0.0.1;port=5531', '_DBUSER_', '_DBPASSWORD_');" }, "perl" : { "dbi" : "$dbh=DBI->connect( 'DBI:mysql:host=127.0.0.1;port=_SERVERPORT_', '_DBUSER_', '_DBPASSWORD_')" }, "python" : { "mysql.connector" : "cnx = mysql.connector.connect(user='_DBUSER_', password='_DBPASSWORD_', host='127.0.0.1', port=_SERVERPORT_, database='test')" }, "java" : { "DriverManager" : "con=DriverManager.getConnection(\\\"jdbc:mysql://127.0.0.1:_SERVERPORT_/test\\\", \\\"_DBUSER_\\\", \\\"_DBPASSWORD_\\\")" }, "ruby" : { "mysql" : "connection = Mysql.new '127.0.0.1', '_DBUSER_', '_DBPASSWORD_', 'test', _SERVERPORT_" }, "shell" : { "generic": "_BASEDIR_/bin/mysql -h 127.0.0.1 -P _SERVERPORT_ -u _DBUSER_ -p_DBPASSWORD_" } } } END_CONNECTION_JSON 'my.sh' => <<'MY_SCRIPT', #!_BINBASH_ __LICENSE__ if [ "$1" = "" ] then echo "syntax my sql{dump|binlog|admin} arguments" exit fi __SBINSTR_SH__ SBDIR=_HOME_DIR_/_SANDBOXDIR_ BASEDIR=_BASEDIR_ export LD_LIBRARY_PATH=$BASEDIR/lib:$BASEDIR/lib/mysql:$LD_LIBRARY_PATH export DYLD_LIBRARY_PATH=$BASEDIR/lib:$BASEDIR/lib/mysql:$DYLD_LIBRARY_PATH MYSQL=$BASEDIR/bin/mysql SUFFIX=$1 shift MYSQLCMD="$BASEDIR/bin/my$SUFFIX" NODEFAULT=(myisam_ftdump myisamlog mysql_config mysql_convert_table_format mysql_find_rows mysql_fix_extensions mysql_fix_privilege_tables mysql_secure_installation mysql_setpermission mysql_tzinfo_to_sql mysql_config_editor mysql_waitpid mysql_zap mysqlaccess mysqlbinlog mysqlbug mysqldumpslow mysqlhotcopy mysqltest mysqltest_embedded) DEFAULTSFILE="--defaults-file=$SBDIR/my.sandbox.cnf" for NAME in ${NODEFAULT[@]} do if [ "my$SUFFIX" = "$NAME" ] then DEFAULTSFILE="" break fi done if [ -f $MYSQLCMD ] then $MYSQLCMD $DEFAULTSFILE "$@" else echo "$MYSQLCMD not found " fi MY_SCRIPT 'proxy_start.sh' => <<'PROXY_START_SCRIPT', #!_BINBASH_ __LICENSE__ PROXY_BIN=/usr/local/sbin/mysql-proxy HOST='127.0.0.1' $PROXY_BIN --proxy-backend-addresses=$HOST:_SERVERPORT_ "$@" PROXY_START_SCRIPT 'change_ports.sh' => <<'CHANGE_PORTS_SCRIPT', #!_BINBASH_ __LICENSE__ __SBINSTR_SH__ OLD_PORT=_SERVERPORT_ if [ "$1" = "" ] then echo "new port required" exit else NEW_PORT=$1 fi if [ $OLD_PORT = $NEW_PORT ] then echo Old port and new port must be different. exit fi PERL_SCRIPT1='BEGIN{$old=shift;$new=shift};' PERL_SCRIPT2='s/sandbox$old/sandbox$new/g;' PERL_SCRIPT3='s/\b$old\b/$new/' PERL_SCRIPT="$PERL_SCRIPT1 $PERL_SCRIPT2 $PERL_SCRIPT3" SCRIPTS1="start stop send_kill clear status restart my.sandbox.cnf " SCRIPTS2="load_grants my use $0" SCRIPTS="$SCRIPTS1 $SCRIPTS2" for SCRIPT in $SCRIPTS do perl -i.port.bak -pe "$PERL_SCRIPT" $OLD_PORT $NEW_PORT $SCRIPT done echo "($PWD) The old scripts have been saved as filename.port.bak" CHANGE_PORTS_SCRIPT 'change_paths.sh' => <<'CHANGE_PATHS_SCRIPT', #!_BINBASH_ __LICENSE__ if [ "$1" = "" ] then OLD_SB_LOCATION=_HOME_DIR_/_SANDBOXDIR_ else OLD_SB_LOCATION=$1 fi __SBINSTR_SH__ if [ "$2" = "" ] then NEW_SB_LOCATION=$PWD else NEW_SB_LOCATION=$2 fi if [ $OLD_SB_LOCATION = $NEW_SB_LOCATION ] then echo Old location and new location must be different. echo Move the sandbox to the new location and then run this script. exit fi if [ ! -d "$NEW_SB_LOCATION" ] then echo "new location must be a directory" exit fi PERL_SCRIPT1='BEGIN{$old=shift;$new=shift};' PERL_SCRIPT2='s/$old/$new/g' PERL_SCRIPT="$PERL_SCRIPT1 $PERL_SCRIPT2" SCRIPTS1="start stop send_kill clear status restart my.sandbox.cnf " SCRIPTS2="load_grants my use $0" SCRIPTS="$SCRIPTS1 $SCRIPTS2" for SCRIPT in $SCRIPTS do perl -i.bak -pe "$PERL_SCRIPT" $OLD_SB_LOCATION $NEW_SB_LOCATION $SCRIPT done echo "($PWD) The old scripts have been saved as filename.path.bak" CHANGE_PATHS_SCRIPT 'sandbox_action.pl' => <<'SANDBOX_ACTION_SCRIPT', #!_BINPERL_ __LICENSE__ use strict; use warnings; use MySQL::Sandbox qw(sbinstr); my $DEBUG = $MySQL::Sandbox::DEBUG; my $action_list = 'use|start|stop|status|clear|restart|send_kill'; my $action = shift or die "action required {$action_list}\n"; $action =~/^($action_list)$/ or die "action must be one of {$action_list}\n"; my $sandboxdir = $0; sbinstr($action); $sandboxdir =~ s{[^/]+$}{}; $sandboxdir =~ s{/$}{}; my $command = $ARGV[0]; if ($action eq 'use' and !$command) { die "action 'use' requires a command\n"; } my @dirs = glob("$sandboxdir/*"); for my $dir (@dirs) { if (-d $dir) { if ($action eq "use") { if ( -x "$dir/use_all" ) { print "executing -- $dir/use_all $command\n" if $DEBUG; system(qq($dir/use_all "$command")); } elsif ( -x "$dir/use" ) { print "executing -- $dir/use $command\n" if $DEBUG; system(qq(echo "$command" | $dir/use)); } } elsif ( -x "$dir/${action}_all") { print "-- executing $dir/${action}_all\n" if $DEBUG; system("$dir/${action}_all", @ARGV) } elsif ( -x "$dir/$action") { print "-- executing $dir/$action\n" if $DEBUG; system("$dir/$action", @ARGV) } } } SANDBOX_ACTION_SCRIPT 'plugin.conf' => <<'PLUGIN_CONF', # # Plugin configuration file # To use this template, see # sbtool -o plugin # $plugin_definition = { innodb => { minimum_version => '5.1.45', all_servers => { operation_sequence => [qw(stop options_file start sql_commands )], options_file => [ 'ignore_builtin_innodb', 'plugin-load=' .'innodb=ha_innodb_plugin.so;' .'innodb_trx=ha_innodb_plugin.so;' .'innodb_locks=ha_innodb_plugin.so;' .'innodb_lock_waits=ha_innodb_plugin.so;' .'innodb_cmp=ha_innodb_plugin.so;' .'innodb_cmp_reset=ha_innodb_plugin.so;' .'innodb_cmpmem=ha_innodb_plugin.so;' .'innodb_cmpmem_reset=ha_innodb_plugin.so', 'default-storage-engine=InnoDB', 'innodb_file_per_table=1', 'innodb_file_format=barracuda', 'innodb_strict_mode=1', ], sql_commands => [ 'select @@innodb_version;', ], startup_file => [ ], }, }, semisynch => { minimum_version => '5.5.2', master => { operation_sequence => [qw(stop options_file start sql_commands )], options_file => [ 'plugin-load=rpl_semi_sync_master=semisync_master.so', 'rpl_semi_sync_master_enabled=1' ], sql_commands => [ 'select @@rpl_semi_sync_master_enabled;' ], startup_file => [] }, slave => { operation_sequence => [qw(stop options_file start sql_commands )], options_file => [ 'plugin-load=rpl_semi_sync_slave=semisync_slave.so', 'rpl_semi_sync_slave_enabled=1' ], sql_commands => [ 'select @@rpl_semi_sync_slave_enabled;' ], startup_file => [] }, }, gearman => { minimum_version => '5.0', all_servers => { operation_sequence => [qw(start sql_commands options_file startup_file restart )], options_file => [ 'init-file=startup.sql' ], sql_commands => [ 'CREATE FUNCTION gman_do RETURNS STRING SONAME "libgearman_mysql_udf.so";', 'CREATE FUNCTION gman_do_high RETURNS STRING SONAME "libgearman_mysql_udf.so";', 'CREATE FUNCTION gman_do_low RETURNS STRING SONAME "libgearman_mysql_udf.so";', 'CREATE FUNCTION gman_do_background RETURNS STRING SONAME "libgearman_mysql_udf.so";', 'CREATE FUNCTION gman_do_high_background RETURNS STRING SONAME "libgearman_mysql_udf.so";', 'CREATE FUNCTION gman_do_low_background RETURNS STRING SONAME "libgearman_mysql_udf.so";', 'CREATE AGGREGATE FUNCTION gman_sum RETURNS INTEGER SONAME "libgearman_mysql_udf.so";', 'CREATE FUNCTION gman_servers_set RETURNS STRING SONAME "libgearman_mysql_udf.so";', ], startup_file => [ 'set @a := (select gman_servers_set("127.0.0.1"));', 'use test ;', 'create table if not exists startup (msg text, ts timestamp);', 'insert into startup (msg) values (@a);', ] }, }, }; PLUGIN_CONF 'test_replication.sh' => <<'TEST_REPLICATION', #!_BINBASH_ __LICENSE__ if [ -x ./m ] then MASTER=./m elif [ -x ./n1 ] then MASTER=./n1 else echo "# No master found" exit 1 fi $MASTER -e 'create schema if not exists test' $MASTER test -e 'drop table if exists t1' $MASTER test -e 'create table t1 (i int not null primary key, msg varchar(50), d date, t time, dt datetime, ts timestamp)' $MASTER test -e "insert into t1 values (1, 'test sandbox 1', '2015-07-16', '11:23:40','2015-07-17 12:34:50', null)" sleep 0.5 $MASTER test -e "insert into t1 values (2, 'test sandbox 2', '2015-07-17', '11:23:41','2015-07-17 12:34:51', null)" MASTER_RECS=$($MASTER -BN -e 'select count(*) from test.t1') master_status=master_status$$ slave_status=slave_status$$ $MASTER -e 'show master status\G' > $master_status master_binlog=$(grep 'File:' $master_status | awk '{print $2}' ) master_pos=$(grep 'Position:' $master_status | awk '{print $2}' ) echo "# Master log: $master_binlog - Position: $master_pos - Rows: $MASTER_RECS" rm -f $master_status FAILED=0 PASSED=0 function ok_equal { fact="$1" expected="$2" msg="$3" if [ "$fact" == "$expected" ] then echo -n "ok" PASSED=$(($PASSED+1)) else echo -n "not ok - (expected: <$expected> found: <$fact>) " FAILED=$(($FAILED+1)) fi echo " - $msg" } function test_summary { TESTS=$(($PASSED+$FAILED)) if [ -n "$TAP_TEST" ] then echo "1..$TESTS" else PERCENT_PASSED=$(($PASSED/$TESTS*100)) PERCENT_FAILED=$(($FAILED/$TESTS*100)) printf "# TESTS : %5d\n" $TESTS printf "# FAILED: %5d (%5.1f%%)\n" $FAILED $PERCENT_FAILED printf "# PASSED: %5d (%5.1f%%)\n" $PASSED $PERCENT_PASSED fi } for SLAVE_N in 1 2 3 4 5 6 7 8 9 do N=$(($SLAVE_N+1)) unset SLAVE if [ -x ./s$SLAVE_N ] then SLAVE=./s$SLAVE_N elif [ -x ./n$N ] then SLAVE=./n$N fi if [ -n "$SLAVE" ] then echo "# Testing slave #$SLAVE_N" if [ -f set_circular_replication.sh ] then sleep 3 else S_READY=$($SLAVE -BN -e "select master_pos_wait('$master_binlog', $master_pos,60)") # master_pos_wait can return 0 or a positive number for successful replication # Any result that is not NULL or -1 is acceptable if [ "$S_READY" != "-1" -a "$S_READY" != "NULL" ] then S_READY=0 fi ok_equal $S_READY 0 "Slave #$SLAVE_N acknowledged reception of transactions from master" fi $SLAVE -e 'show slave status\G' > $slave_status IO_RUNNING=$(grep -w Slave_IO_Running $slave_status | awk '{print $2}') ok_equal $IO_RUNNING Yes "Slave #$SLAVE_N IO thread is running" SQL_RUNNING=$(grep -w Slave_IO_Running $slave_status | awk '{print $2}') ok_equal $SQL_RUNNING Yes "Slave #$SLAVE_N SQL thread is running" rm -f $slave_status [ $FAILED == 0 ] || exit 1 T1_EXISTS=$($SLAVE -BN -e 'show tables from test like "t1"') ok_equal $T1_EXISTS t1 "Table t1 found on slave #$SLAVE_N" T1_RECS=$($SLAVE -BN -e 'select count(*) from test.t1') ok_equal $T1_RECS $MASTER_RECS "Table t1 has $MASTER_RECS rows on #$SLAVE_N" fi done test_summary TEST_REPLICATION 'show_binlog.sh' => <<'SHOW_BINLOG', #!_BINBASH_ __LICENSE__ curdir="_HOME_DIR_/_SANDBOXDIR_" cd $curdir if [ ! -d ./data ] then echo "$curdir/data not found" exit 1 fi # Checks if the output is a terminal or a pipe if [ -t 1 ] then echo "###################### WARNING ####################################" echo "# You are not using a pager." echo "# The output of this script can be quite large." echo "# Please pipe this script with a pager, such as 'less' or 'vim -'" echo "# ENTER 'q' to exit or simply RETURN to continue without a pager" read answer if [ "$answer" == "q" ] then exit fi fi pattern=$1 [ -z "$pattern" ] && pattern='[0-9]*' if [ "$pattern" == "-h" -o "$pattern" == "--help" -o "$pattern" == "-help" -o "$pattern" == "help" ] then echo "# Usage: $0 [BINLOG_PATTERN] " echo "# Where BINLOG_PATTERN is a number, or part of a number used after 'mysql-bin'" echo "# (The default is '[0-9]*]')" echo "# examples:" echo "# ./show_binlog 000001 | less " echo "# ./show_binlog 000012 | vim - " echo "# ./show_binlog | grep -i 'CREATE TABLE'" exit 0 fi # set -x last_binlog=$(ls -lotr data/mysql-bin.$pattern | tail -n 1 | awk '{print $NF}') if [ -z "$last_binlog" ] then echo "No binlog found in $curdir/data" exit 1 fi (printf "#\n# Showing $last_binlog\n#\n" ; ./my sqlbinlog --verbose $last_binlog ) SHOW_BINLOG 'show_relaylog.sh' => <<'SHOW_RELAYLOG', #!_BINBASH_ __LICENSE__ curdir="_HOME_DIR_/_SANDBOXDIR_" cd $curdir if [ ! -d ./data ] then echo "$curdir/data not found" exit 1 fi # Checks if the output is a terminal or a pipe if [ -t 1 ] then echo "###################### WARNING ####################################" echo "# You are not using a pager." echo "# The output of this script can be quite large." echo "# Please pipe this script with a pager, such as 'less' or 'vim -'" echo "# ENTER 'q' to exit or simply RETURN to continue without a pager" read answer if [ "$answer" == "q" ] then exit fi fi relay_basename=$1 [ -z "$relay_basename" ] && relay_basename='mysql-relay' pattern=$2 [ -z "$pattern" ] && pattern='[0-9]*' if [ "$pattern" == "-h" -o "$pattern" == "--help" -o "$pattern" == "-help" -o "$pattern" == "help" ] then echo "# Usage: $0 [ relay-base-name [BINLOG_PATTERN]] " echo "# Where relay-basename is the initial part of the relay ('$relay_basename')" echo "# and BINLOG_PATTERN is a number, or part of a number used after '$relay_basename'" echo "# (The default is '[0-9]*]')" echo "# examples:" echo "# ./show_relaylog relay-log-alpha 000001 | less " echo "# ./show_relaylog relay-log 000012 | vim - " echo "# ./show_relaylog | grep -i 'CREATE TABLE'" exit 0 fi # set -x last_relaylog=$(ls -lotr data/$relay_basename.$pattern | tail -n 1 | awk '{print $NF}') if [ -z "$last_relaylog" ] then echo "No relay log found in $curdir/data" exit 1 fi (printf "#\n# Showing $last_relaylog\n#\n" ; ./my sqlbinlog --verbose $last_relaylog ) SHOW_RELAYLOG 'add_option.sh' => <<'ADD_OPTION', #!_BINBASH_ __LICENSE__ curdir="_HOME_DIR_/_SANDBOXDIR_" cd $curdir if [ -z "$*" ] then echo "# Syntax $0 options-for-my.cnf [more options] " exit fi CHANGED='' for OPTION in $@ do option_exists=$(grep $OPTION ./my.sandbox.cnf) if [ -z "$option_exists" ] then echo "$OPTION" >> my.sandbox.cnf echo "# option '$OPTION' added to configuration file" CHANGED=1 else echo "# option '$OPTION' already exists configuration file" fi done if [ -n "$CHANGED" ] then ./restart fi ADD_OPTION ); # --- END SCRIPTS IN CODE --- my $license_text = <<'LICENSE'; # The MySQL Sandbox # Copyright (C) 2006-2015 Giuseppe Maxia # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. LICENSE sub license_text { return $license_text; } sub parse_options_low_level_make_sandbox { return \%parse_options_low_level_make_sandbox; } sub parse_options_replication { return \%parse_options_replication; } sub parse_options_many { return \%parse_options_many; } sub parse_options_sbtool { return \%parse_options_sbtool; } sub parse_options_custom_many { return \%parse_options_custom_many; } sub scripts_in_code { return \%scripts_in_code; } my $readme_multiple = <<'END_README_MULTIPLE'; This is a composite sandbox. Each node is independent, without any replication relationship to the others To operate each node, use ./n1 [options] # (= ./node1/use [options]) ./n2 [options] # (= ./node2/use [options]) ... ./nN [options] # (= ./nodeN/use [options]) END_README_MULTIPLE my $readme_circular = <<'END_README_CIRCULAR'; This is a composite sandbox, where each node is both a master and a slave (in circular replication) To operate each node, use ./n1 [options] # (= ./node1/use [options]) ./n2 [options] # (= ./node2/use [options]) ... ./nN [options] # (= ./nodeN/use [options]) END_README_CIRCULAR my $readme_master_slave = <<'END_README_MASTER_SLAVE'; This is a composite replication sandbox, having one master and many slaves. To operate the master, use ./m [options] # (= ./master/use) To operate the slaves, use ./s1 [options] # (= ./node1/use [options]) ./s2 [options] # (= ./node2/use [options]) ... ./sN [options] # (= ./nodeN/use [options]) END_README_MASTER_SLAVE my $readme_common_replication = <<'END_README_COMMON_REPLICATION'; ./to check the status of all slaves, use: ./check_slaves END_README_COMMON_REPLICATION my $readme_common = <<'END_README_COMMON'; To run a SQL command in all servers, use: ./use_all {query} To connect to this sandbox, use the information stored inside 'connection.json' or 'default_connection.json'. Simple administrative tasks can be performed using: ./start_all [options] : starts all servers ./stop_all : stops all servers ./status_all : tells the status of all servers ./clear_all : stops andremoves the contents from all servers (WARNING: dangerous) ./restart_all [options] : restarts all servers More information is available inside the README file within each directory below. The full manual is available using: perldoc MySQL::Sandbox A task-oriented user guide is also available: perldoc MySQL::Sandbox::Recipes END_README_COMMON sub get_readme_common_replication { return $readme_common_replication; } sub get_readme_common { return $readme_common; } sub get_readme_multiple { return MySQL::Sandbox::credits() . "\n" . $readme_multiple; } sub get_readme_circular { return MySQL::Sandbox::credits() . "\n" . $readme_circular; } sub get_readme_master_slave { return MySQL::Sandbox::credits() . "\n" . $readme_master_slave; } 1; __END__ =head1 NAME MySQL::Sandbox::Scripts - Script templates for MySQL Sandbox =head1 PURPOSE This package is a collection of data and scripts templates for MySQL::Sandbox. It is not supposed to be used stand alone. It is an ancillary package. For a reference manual, see L. For a cookbook, see L. =head1 COPYRIGHT Version 3.1 Copyright (C) 2006-2015 Giuseppe Maxia Home Page http://github.com/datacharmer =head1 LEGAL NOTICE Copyright 2006-2015 Giuseppe Maxia Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. MySQL-Sandbox-3.1.04/bin/deploy_to_remote_sandboxes.sh000755 000765 000024 00000012170 12566053633 022777 0ustar00gmaxstaff000000 000000 #!/bin/bash # The MySQL Sandbox # Copyright (C) 2006-2015 Giuseppe Maxia # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. [ -z "$MYSQL_VERSION" ] && MYSQL_VERSION=5.5.30 [ -z "$MYSQL_PORT" ] && MYSQL_PORT=15530 [ -z "$SANDBOX_DIR" ] && SANDBOX_DIR=remote_sb NODES_LIST= TARBALL= function show_help { echo "Deploy to remote sandboxes. " echo "Usage: $0 [options] " echo '-h => help' echo "-P port => MySQL port ($MYSQL_PORT)" echo "-d sandbox dir => sandbox directory name ($SANDBOX_DIR)" echo "-m version => MySQL version ($MYSQL_VERSION)" echo "-l list of nodes => list of nodes where to deploy" echo "-s server-ids => list of server IDs to use (default: (10 20 30 40 ...))" echo '-t tarball => MySQL tarball to install remotely (none)' echo '-y my.cnf => MySQL configuration file to use as template (none)' echo "" echo "This command takes the list of nodes and installs a MySQL sandbox in each one." echo "You must have ssh access to the remote nodes, or this script won't work." exit 1 } SERVER_IDS=(`seq 10 10 200`) args=$(getopt hs:P:m:d:l:t:y: $*) if [ $? != 0 ] then show_help fi set -- $args for i do case "$i" in -h) show_help ;; -d) export SANDBOX_DIR=$2 shift shift ;; -l) NODES_LIST=$(echo $2 | tr ',' ' ') count=0 for NODE in $NODES_LIST do NODES[$count]=$NODE count=$(($count+1)) done export UPDATE_USER_VALUES= shift shift ;; -m) export MYSQL_VERSION=$2 shift shift ;; -P) export MYSQL_PORT=$2 shift shift ;; -s) I=0 for n in $(echo $2 | tr ',' ' ' ) do SERVER_IDS[$I]=$n; I=$(($I+1)) done shift shift ;; -t) export TARBALL=$2 shift shift ;; -y) export MY_CNF=$2 shift shift ;; --) shift break ;; esac done if [ -z "$NODES_LIST" ] then echo "You must provide a nodes list" show_help fi # remove the sandbox if it already exists for HOST in ${NODES[*]} do ssh $HOST "if [ -d $HOME/sandboxes/$SANDBOX_DIR ] ; then sbtool -o delete -s $HOME/sandboxes/$SANDBOX_DIR > /dev/null ; fi" done BUILD_SB=$HOME/build_sb.sh echo "#!/bin/bash" > $BUILD_SB echo 'SANDBOX_EXISTS=$(for P in `echo $PATH | tr ":" " "` ; do if [ -f $P/make_sandbox ] ; then echo $P/make_sandbox ; fi; done)' >> $BUILD_SB echo 'if [ -z "$SANDBOX_EXISTS" ] ; then hostname; echo "make_sandbox not found in PATH" ; exit 1; fi' >> $BUILD_SB MY_TEMPLATE=$my_template$$.cnf if [ -n "$MY_CNF" ] then if [ ! -f $MY_CNF ] then echo "File '$MY_CNF' not found" exit 1 fi cp $MY_CNF $HOME/$MY_TEMPLATE echo "MY_CNF=\$HOME/$MY_TEMPLATE" >> $BUILD_SB fi echo 'SANDBOX_OPTIONS="--no_confirm --no_show"' >> $BUILD_SB echo 'if [ -n "$MY_CNF" ] ; then SANDBOX_OPTIONS="$SANDBOX_OPTIONS --my_file=$MY_CNF" ; fi ' >> $BUILD_SB echo 'SANDBOX_OPTIONS="$SANDBOX_OPTIONS -c server-id=$1 -c default_storage_engine=innodb -c log-bin=mysql-bin -c log-slave-updates -c innodb_flush_log_at_trx_commit=1"' >> $BUILD_SB echo 'export SANDBOX_OPTIONS="$SANDBOX_OPTIONS -c max_allowed_packet=48M --remote_access=%"' >> $BUILD_SB if [ -n "$TARBALL" ] then BASE_TARBALL=$(basename $TARBALL) echo "make_sandbox \$HOME/opt/mysql/$BASE_TARBALL -- --sandbox_port=$MYSQL_PORT \\" >> $BUILD_SB else echo "make_sandbox $MYSQL_VERSION -- --sandbox_port=$MYSQL_PORT \\" >> $BUILD_SB fi echo " --sandbox_directory=$SANDBOX_DIR \$SANDBOX_OPTIONS" >> $BUILD_SB # echo "if [ -f \$HOME/$MY_TEMPLATE ] ; then rm -f \$HOME/$MY_TEMPLATE ; fi " chmod +x $BUILD_SB SERVER_ID_COUNTER=0 for HOST in ${NODES[*]} do if [ -n "$TARBALL" ] then ssh $HOST 'if [ ! -d $HOME/opt/mysql ] ; then mkdir -p $HOME/opt/mysql ; fi' scp -p $TARBALL $HOST:~/opt/mysql fi scp -p $BUILD_SB $HOST:$BUILD_SB scp -p $HOME/$MY_TEMPLATE $HOST:$MY_TEMPLATE ssh $HOST $BUILD_SB ${SERVER_IDS[$SERVER_ID_COUNTER]} SERVER_ID_COUNTER=$(($SERVER_ID_COUNTER+1)) done echo "Connection parameters:" echo "datadir=~/sandboxes/$SANDBOX_DIR/data" echo "options file=~/sandboxes/$SANDBOX_DIR/my.sandbox.cnf" echo "port=$MYSQL_PORT" echo "" MySQL-Sandbox-3.1.04/bin/low_level_make_sandbox000755 000765 000024 00000104422 12631403277 021450 0ustar00gmaxstaff000000 000000 #!/usr/bin/perl # low_level_make_sandbox # The MySQL Sandbox # Copyright (C) 2006-2015 Giuseppe Maxia # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. use strict; use warnings; use English qw( -no_match_vars ); use Data::Dumper; use Getopt::Long qw(:config no_ignore_case ); use MySQL::Sandbox qw( find_safe_port_and_directory exists_in_path runs_as_root use_env sbinstr fix_server_uuid greater_version split_version); use MySQL::Sandbox::Scripts; my $DEBUG = $MySQL::Sandbox::DEBUG; #my $install_dir; #$install_dir = $PROGRAM_NAME; #$install_dir =~ s{/\w+(\.pl)?$}{}; if ($ENV{HOME} =~ / /) { die "# The variable \$HOME contains spaces. Please fix this problem before continuing\n"; } my $msb = MySQL::Sandbox->new(); runs_as_root(); check_sandbox_dir(); check_tmp_dir(); my %scripts_in_code = %{ MySQL::Sandbox::Scripts::scripts_in_code() }; my $license_text = MySQL::Sandbox::Scripts::license_text(); $msb->parse_options(MySQL::Sandbox::Scripts::parse_options_low_level_make_sandbox()); # print Dumper $msb;exit; # my %{$msb->{options}} = map { $_ , $msb->{parse_options}{$_}{'value'}} keys %{$msb->{parse_options}}; my %default_values = %{ $msb->{options}}; my %user_values; #print Dumper \%{$msb->{options}}; exit; GetOptions ( map { $msb->{parse_options}{$_}{parse}, \$msb->{options}{$_} } grep { $msb->{parse_options}{$_}{parse}} keys %{$msb->{parse_options}} ) or $msb->get_help(); # # We are not expecting bare arguments # if (@ARGV){ die "unexpected arguments <@ARGV>\n"; } $msb->get_help() if $msb->{options}{'help'}; # print Dumper(\%{$msb->{options}}, \@ARGV); exit; my $with_space=''; for my $option (qw(upper_directory basedir datadir)) { next unless (defined $msb->{options}{$option}); if ($msb->{options}{$option} =~ / /) { $with_space .= " $option"; } } if ($with_space) { die "# Options <$with_space> contain space. Aborting\n"; } $msb->{options}{globaltmpdir} = $ENV{TMPDIR}; for my $opt (keys %{$msb->{options}} ) { #unless (defined $default_values{$opt} and defined $msb->{options}{$opt} ) { # print Data::Dumper->Dump([ $default_values{$opt}, # $msb->{options}{$opt}, $opt], ['default','option', 'opt']); # die "undefined option\n"; #} # next unless $default_values{$opt}; if ((not defined $default_values{$opt}) or ($default_values{$opt} ne $msb->{options}{$opt} )) { $user_values{$opt} = $msb->{options}{$opt}; } } %default_values = (); $msb->{options}{'my_clause'} = [] unless $msb->{options}{'my_clause'} ; # print Dumper($msb->{options}{'my_clause'});exit; if ( $msb->{options}{'high_performance'}) { my @perf_clauses = ( 'innodb-thread-concurrency=0', 'sync_binlog=0', 'innodb-log-buffer-size=100M', # 'innodb-additional-mem-pool-size=50M', # deprecated (removed in MySQL 5.7.4) 'max-connections=350', 'max_allowed_packet=48M', 'innodb_buffer_pool_size=512M', 'innodb-log-file-size=50M', 'innodb-flush-method=O_DIRECT' ); for my $clause (@perf_clauses) { unshift @{ $msb->{options}{'my_clause'}}, $clause; } } if ($msb->{options}{'slaveof'} or $msb->{options}{'master'}) { for my $clause (('log-bin=mysql-bin', 'server-id=' . $msb->{options}{sandbox_port}, 'relay-log=mysql-relay', 'relay-log-index=mysql-relay' )) { unshift @{ $msb->{options}{'my_clause'}}, $clause; } } # my $mysql_version = qx($msb->{options}{basedir}/bin/mysql_config --version); if ($msb->{options}{'interactive'}) { $msb->{options}{no_confirm} = 0; select_interactively() if $msb->{options}{'interactive'}; } $DEBUG = 1 if $msb->{options}{'verbose'}; $msb->{options}{'verbose'} = 1 if $DEBUG; if ( -f "$ENV{'HOME'}/.msandboxrc") { if ( $msb->{options}{'conf_file'}) { # conf file given. Neet to concatenate default file and # rc file my $tmp_conf_file = "$ENV{TMPDIR}/msandboxrc.cnf"; my $result = system (qq( cat $ENV{'HOME'}/.msandboxrc $msb->{options}{'conf_file'} > $tmp_conf_file )); if ($result) { die "can't create $tmp_conf_file ($CHILD_ERROR)\n"; } $msb->{options}{'conf_file'} = $tmp_conf_file; } else { $msb->{options}{'conf_file'} = "$ENV{'HOME'}/.msandboxrc"; } } if ( $msb->{options}{'conf_file'}) { open my $CONF, q{<}, $msb->{options}{'conf_file'} or die "error opening $msb->{options}{'conf_file'}. ($ERRNO)\n"; print "reading configuration file ($msb->{options}{'conf_file'})\n" if $DEBUG; while (<$CONF>) { next if / ^ \s* $ /x; next if / ^ \s* [#] /x; chomp; my ($key, $value); if ( /^ \s* (\S+) \s* = \s* (.+)?/x) { ($key, $value) = ($1, $2); } elsif ( /^ \s* ( \S+ ) \s* $/x) { ($key, $value) = ($1, ''); next unless $msb->{parse_options}{$key}; # print "++ $msb->{parse_options}{$key}{'value'} \n"; if ($msb->{parse_options}{$key}{'value'} =~ /^\d+$/) { $value = $msb->{parse_options}{$key}{'value'} ? 0 : 1 ; } } else { next; } # print ">>> $key ($value)\n"; if (exists $user_values{$key}) { # skipping file options if they have been entered in the command line # print "skipping option $key\n"; next; } elsif (exists $msb->{options}{$key} ) { $value = q{} unless defined $value; if ( $value =~ s/^\$//x ) { $value = $ENV{$value}; } if ( $msb->{parse_options}{ $key }{'parse'} =~ /\@/) { $msb->{options}{ $key } = [ split /\s*;\s*/, $value ]; } else { # print "assigning <$key> = '$value'\n"; $msb->{options}{$key} = $value; } } else { die "Option '$key' not recognized - File $msb->{options}{'conf_file'} - Line $.\n"; } } close $CONF; } # # options to skip from the imported my.cnf file # my %skip_options = ( 'user' => 1, 'port' => 1, 'socket' => 1, 'datadir' => 1, 'basedir' => 1, 'tmpdir' => 1, 'pid-file' => 1, 'server-id' => 1, ); # # placeholders used in the installation files # with their corresponding values in %{$msb->{options}} # my %replace_options = ( _INSTALL_VERSION_ => 'install_version', _DBUSER_ => 'db_user', _REMOTE_ACCESS_ => 'remote_access', _DBUSERRO_ => 'ro_user', _DBUSERRW_ => 'rw_user', _DBUSERREPL_ => 'repl_user', _DBPASSWORD_ => 'db_password', _DB_REPL_PASSWORD_ => 'repl_password', _OSUSER_ => 'operating_system_user', _BASEDIR_ => 'basedir', _TMPDIR_ => 'tmpdir', _GLOBALTMPDIR_ => 'globaltmpdir', _BINBASH_ => 'binbash', _BINPERL_ => 'binperl', _HOME_DIR_ => 'upper_directory', _SANDBOXDIR_ => 'sandbox_directory', _SERVERPORT_ => 'sandbox_port', _MORE_OPTIONS_ => 'more_options', _MYSQL_PROMPT_ => 'mysql_prompt', _MYSQLDSAFE_ => 'mysqld_safe', _EVENTS_OPTIONS_ => 'events_options', _SLOW_QUERY_LOG_ => 'slow_query_log', _GENERAL_LOG_ => 'general_log', _BIND_ADDRESS_ => 'bind_address', _MSB_VERSION_ => 'msb_version', _LOWER_CASE_TABLE_NAMES_ => 'lower_case_table_names', _HISTORY_DIR_ => 'history_dir', ); $msb->{options}{msb_version} = $MySQL::Sandbox::VERSION; if ($msb->{options}{db_user} =~ /\@/) { my ($user, $host) = split /\@/, $msb->{options}{db_user}; $msb->{options}{db_user} = $user; $msb->{options}{remote_access} = $host; } if ($OSNAME =~ /darwin/) { $msb->{options}{lower_case_table_names} = 2; } else { $msb->{options}{lower_case_table_names} = 0; } if ( ($msb->{options}{remote_access} eq $MySQL::Sandbox::default_users{remote_access}) && ($msb->{options}{bind_address} eq '127.0.0.1') ) { # Do nothing. # Make sure that we honor the defaults # } elsif ( ($msb->{options}{remote_access} ne $MySQL::Sandbox::default_users{remote_access}) && ($msb->{options}{bind_address} ne '127.0.0.1') ) { # Do nothing. # Both defaults were changed. # Make sure that we let user change both values # } elsif ( ($msb->{options}{remote_access} ne $MySQL::Sandbox::default_users{remote_access}) && ($msb->{options}{remote_access} ne '127.0.0.1') && ($msb->{options}{bind_address} eq '127.0.0.1') ) { # remote_access changed. Make sure that we can access the server $msb->{options}{bind_address} = '0.0.0.0'; } elsif ( ($msb->{options}{bind_address} ne '0.0.0.0') && ($msb->{options}{remote_access} ne '%') ) { # Customized bind address # We adjust the remote access to match it $msb->{options}{remote_access} = $msb->{options}{bind_address}; } elsif ($msb->{options}{bind_address} ne '127.0.0.1') { $msb->{options}{remote_access} = $msb->{options}{bind_address}; } for my $opt (qw(db_user remote_access ro_user rw_user repl_user db_password repl_password)) { if (defined $msb->{options}{$opt}) { $MySQL::Sandbox::default_users{$opt} = $msb->{options}{$opt}; } } unless ( ($msb->{options}{'sandbox_port'} =~ /^ \d{3,} $ /x) && ($msb->{options}{'sandbox_port'} > 1024 ) && ($msb->{options}{'sandbox_port'} <= 64000)) { $msb->get_help( "sandbox_port option must be a port number between 1025 and 64000 (currently requested $msb->{options}{'sandbox_port'} ) \n"); } if ($msb->{options}{check_port} and (! $msb->{options}{no_check_port}) ) { ( $msb->{options}{'sandbox_port'}, $msb->{options}{'sandbox_directory'}) = find_safe_port_and_directory( $msb->{options}{'sandbox_port'}, $msb->{options}{'sandbox_directory'}, $msb->{options}{'upper_directory'}) ; } if ($msb->{options}{datadir_from} eq 'archive') { print "You have chosen to install with the 'archive' method.\n"; print "This option is now DEPRECATED.\n"; print "It will be removed soon. Use the 'script' method instead\n"; #chdir $sandbox_directory; #system "tar -xzf $curdir/datadir.$msb->{options}{'install_version'}.tar.gz "; #chdir $curdir; } if ($msb->{options}{datadir_from} eq 'script' and (not $msb->{options}{no_load_grants} ) ) { $msb->{options}{load_grants} = 1; } if ( @{ $msb->{options}{'my_clause'} } ) { $msb->{options}{'more_options'} .= qq(#\n# additional options passed through 'my_clause' \n#\n); for my $clause ( @{ $msb->{options}{'my_clause'} }) { $msb->{options}{'more_options'} .= $clause . "\n"; if ($clause =~ /server.id=(\d+)/) { my $sid=$1; $msb->{options}{fix_server_uuid} = [ $sid, $msb->{options}{install_version}, $msb->{options}{sandbox_port}, "$msb->{options}{upper_directory}/$msb->{options}{sandbox_directory}"]; } } } if ($msb->{options}{my_file} ) { my $fname = $msb->{options}{'my_file'}; unless ( -f $fname ) { $fname = sprintf 'my-%s.cnf', $msb->{options}{my_file}; } my $extended_fname = sprintf '%s/support-files/%s', $msb->{options}{basedir}, $fname; my $share_extended_fname = sprintf '%s/share/mysql/%s', $msb->{options}{basedir}, $fname; if ( -f $fname ) { $msb->{options}{more_options} .= get_more_options($fname); } elsif ( -f $extended_fname ) { $msb->{options}{more_options} .= get_more_options($extended_fname); } elsif ( -f $share_extended_fname ) { $msb->{options}{more_options} .= get_more_options($share_extended_fname); } else { die "configuration file $fname not found\n"; } } # print Dumper(\%{$msb->{options}}); exit; my $bash = 'bash'; unless (exists_in_path($bash)) { $bash = 'tcsh'; } for my $cmd ( ($bash, 'tar', 'gzip') ) { unless ( exists_in_path($cmd) ) { die "$cmd not found. Can't continue\n"; } } my $bin_bash = `which $bash`; ## no critic if ((! $bin_bash) or ( $bin_bash =~ /^no/i) ) { die "can't find the 'bash' shell\n"; } chomp $bin_bash; $msb->{options}{'binbash'} = $bin_bash; my $bin_perl = `which perl`; ## no critic if ((! $bin_perl) or ( $bin_perl =~ /^no/i) ) { die "can't find the 'perl' interpreter\n"; } chomp $bin_perl; $msb->{options}{'binperl'} = $bin_perl; my @supported_versions = @{ MySQL::Sandbox::supported_versions() }; #$msb->{options}{'install_version'} = '5.0' unless $msb->{options}{'install_version'}; die "server version required.\n" unless $msb->{options}{'install_version'}; unless (grep {$_ eq $msb->{options}{'install_version'} } @supported_versions ) { get_help( "specified version ($msb->{options}{'install_version'}) not allowed. Currently accepted are [@supported_versions] "); } # # # # print "<<$msb->{options}{ 'install_version' }>>\n"; if ($msb->{options}{ 'install_version' } ge '5.5' ) { $msb->{options}{events_options} = ' --events '; } else { $msb->{options}{events_options} = ''; } my $sb_datadir = qq($msb->{options}{upper_directory}/$msb->{options}{sandbox_directory}/data); if ($msb->{options}{ 'install_version' } ge '5.1' ) { $msb->{options}{'slow_query_log'} = qq(slow-query-log = on\n) . qq(# slow-query-log-file=$sb_datadir/msandbox-slow.log); $msb->{options}{'general_log'} = qq(general-log = on\n) . qq(# general-log-file=$sb_datadir/msandbox-general.log); } else { $msb->{options}{'slow_query_log'} = qq(log-slow-queries = $sb_datadir/msandbox-slow.log); $msb->{options}{'general_log'} = qq(log = $sb_datadir/msandbox-general.log) ; } if ($msb->{options}{ 'install_version' } eq '3.23' ) { $msb->{options}{'mysql_prompt'} = q{}; $msb->{options}{'mysqld_safe'} = q{safe_mysqld}; } else { $msb->{options}{'mysql_prompt'} = q/prompt=/ . $msb->{options}{prompt_prefix} . $msb->{options}{prompt_body}; $msb->{options}{'mysql_prompt'} =~ s/'//g; $msb->{options}{'mysql_prompt'} =~ s/=/='/; $msb->{options}{'mysql_prompt'} .= "'"; $msb->{options}{'mysqld_safe'} = q{mysqld_safe}; } if ( $msb->{options}{'sandbox_directory'} ) { if ($msb->{options}{'sandbox_directory'} =~ m{/} ) { die " can't be a full path. " . "It's only the name of the directory " . "to create inside $msb->{options}{'upper_directory'}\n"; } unless ( $msb->{options}{ 'no_ver_after_name' } ) { my $ver = $msb->{options}{ 'install_version' }; # $ver =~ tr/./_/d; ## no critic $ver =~ s/\./_/g; unless ($msb->{options}{ 'sandbox_directory'} =~ /$ver$/) { $msb->{options}{'sandbox_directory'} .= $ver; $msb->{options}{ 'no_ver_after_name' } = 1; # 1.6 it will prevent # side effects when loading # options from defaults file } } } else { get_help ('sandbox directory not specified'); } print $msb->credits(); unless ($msb->{options}{no_show}) { print "Installing with the following parameters:\n"; } #open my $CURRENT_CONF , q{>}, "$install_dir/current_options.conf" # or die "error creating current_options.conf ($ERRNO)\n"; if ($msb->{options}{no_show}) { $msb->{options}{no_confirm} =1; } unless ($msb->{options}{no_show}) { for my $key ( sort { $msb->{parse_options}{$a}{so} <=> $msb->{parse_options}{$b}{so} } grep { $msb->{parse_options}{$_}{parse}} keys %{$msb->{parse_options}} ) { next if grep { $key eq $_ } qw/more_options help interactive conf_file no_confirm /; my $is_array = ref($msb->{options}{$key}) && ref($msb->{options}{$key}) eq 'ARRAY'; printf "%-30s = %s\n", $key, $is_array ? join q{ ; }, @{ $msb->{options}{$key} } : ($msb->{options}{$key} || ''); next unless $msb->{options}{$key}; next if $msb->{options}{$key} =~ /^ \s* $/x; } } my $answer = 'y'; unless ($msb->{options}{no_confirm}) { print 'do you agree? ([Y],n) '; $answer = <>; chomp $answer; if ($answer =~ / ^ \s* $ /x) { $answer = 'y'; } } if (lc($answer) eq 'n') { print "Installation interrupted at user's request\n"; # "To repeat this installation with the same options,\n" # "use $PROGRAM_NAME --conf_file=current_options.conf\n"; exit; } my @file_list = (); # my @doc_file_list = ( ['README'], ['COPYING'], ['VERSION'] ); my @MANIFEST = MySQL::Sandbox::Scripts::manifest(); #open my $MANIFEST, q{<}, "$install_dir/MANIFEST" # or die "file MANIFEST not found\n"; my $install_section = 0; print "reading MANIFEST files \n" if $DEBUG; for my $filename ( @MANIFEST) { chomp $filename; next if $filename =~ /^ \s* $/x; unless ($install_section) { $install_section = 1 if $filename =~ /^ \s* [#] \s* INSTALL \s* FILES /x; } next if $filename =~ /^ \s* [#] /x; print "($install_section) ", $filename, qq(\n) if $DEBUG; my $destination = $filename; if ( ( $scripts_in_code{$filename} ) ) { unless ($install_section) { push @file_list, [$filename, $destination]; } } else { die "listed file $filename not found. Package is not complete\n" } } # set_sandbox_dir_scripts(); my $sandbox_directory = sprintf('%s/%s', $msb->{options}{'upper_directory'}, $msb->{options}{'sandbox_directory'}); #if ($curdir eq $sandbox_directory) { # die "installation directory and destination directory are the same. Can't install\n"; #} if ( -d $sandbox_directory ) { if ($msb->{options}{'force'} ) { my $new_datadir = "$sandbox_directory/data"; my $old_datadir = "$sandbox_directory/old_data"; if ( -d $old_datadir) { system "rm -rf $old_datadir"; } if ( -x "$sandbox_directory/stop") { system("$sandbox_directory/stop"); } system "mv $new_datadir $old_datadir"; warn "Directory $new_datadir already exists. Renamed to $old_datadir\n" if $DEBUG; #warn "$sandbox_directory already exists. Overwriting its contents\n" if $DEBUG; #if ( -f "$sandbox_directory/clear") { # system("$sandbox_directory/clear"); #} #if ( -d "$sandbox_directory/data/mysql") { # system("rm -rf $sandbox_directory/data/mysql"); #} } else { die "$sandbox_directory already exists.\n'--force' option not specified.\nInstallation halted\n"; } } else { print "creating $sandbox_directory\n" if $DEBUG; my $result = mkdir $sandbox_directory; if (! $result ) { die "error creating $sandbox_directory\n"; } } my $sandbox_tmpdir = sprintf '%s/tmp', $sandbox_directory; if ($msb->{options}{'tmpdir'}) { $sandbox_tmpdir = $msb->{options}{'tmpdir'}; } else { $msb->{options}{'tmpdir'} = $sandbox_tmpdir; } if ( -f $sandbox_tmpdir) { die "Can't create directory $sandbox_tmpdir (a file of the same name exists)\n"; } unless (-d $sandbox_tmpdir) { mkdir $sandbox_tmpdir or die "Error creating $sandbox_tmpdir ($!)\n"; } set_sandbox_dir_scripts(); for my $file_spec ( @file_list) { #, @doc_file_list) { copy_and_replace($file_spec->[0], $sandbox_directory, $file_spec->[1]); } if ($msb->{options}{datadir_from} eq 'script' ) { my $additional_options = ""; my $script = sprintf '%s/scripts/mysql_install_db', $msb->{options}{basedir} ; my $mysql_version = qx($msb->{options}{basedir}/bin/mysql_config --version); if ($mysql_version) { chomp $mysql_version; my ($major, $minor, $rev) = split_version($mysql_version); $mysql_version=sprintf('%d.%d.%d', $major,$minor, $rev); if (greater_version($mysql_version, '5.7.5' ) && ($major < 10) ) { $additional_options .= ' --insecure' ; } elsif ((greater_version($mysql_version, '5.7.6') ) && ($major < 10)) # exclude MariaDB from this feature { # mysql_install_db is deprecated. It is now replaced by 'mysqld --initialize' # https://dev.mysql.com/doc/refman/5.7/en/mysql-install-db.html # https://dev.mysql.com/doc/refman/5.7/en/data-directory-initialization-mysqld.html # $additional_options .= ' --initialize-insecure --skip-ssl' ; $additional_options .= ' --initialize-insecure' ; $script = sprintf '%s/bin/mysqld', $msb->{options}{basedir} ; } } else { die "Can't determine MySQL version\n"; } if ($script =~ /mysql_install_db/) { unless ( -x $script ) { if ( -e $script ) { die "$script is not executable\n"; } $script = sprintf '%s/bin/mysql_install_db', $msb->{options}{basedir} ; } } if ( -x $script ) { #my $cmd = sprintf '%s --no-defaults --user=%s --basedir=%s --datadir=%s/data --tmpdir=%s/tmp %s', my $cmd = sprintf '%s --no-defaults --user=%s --basedir=%s --datadir=%s/data %s', $script, $msb->{options}{operating_system_user}, $msb->{options}{basedir}, $sandbox_directory, # $sandbox_directory, $ENV{MYSQL_INSTALL_DB} || ''; if ($DEBUG) { print "$cmd $additional_options\n"; } if ($ENV{TRACE_INSTALL}) { # This instruction will never execute unless the user variable is defined. # It is only needed for testing purposes system qq[echo "\$(date) $mysql_version - $cmd $additional_options" >> $ENV{TMPDIR}/trace_install.txt ]; } my $will_abort = 0; my $result = qx($cmd $additional_options 2>&1); if ($CHILD_ERROR) { $will_abort = 1; } $result = '' unless defined $result; my $abort_msg = "error while creating grant tables\n$result\n"; if ($result && ($result =~ /\berror\b/i)) { # We look for the word 'error' in the output while ($result =~ /(.*\berror\b.*)/ig) { my $error_line = $1; # If the line containing 'error' will also say [Warning], we skip it if ($error_line =~ /\[Warning\]/) { print "# Found [Warning]: skipping line containing 'error'\n" if $DEBUG; } else { # otherwise, we mark this operation as an error $will_abort++; } } } if ($DEBUG) { while ($result =~/(.*warning.*)/ig) { print "++ $1\n"; } } if ($will_abort) { die $abort_msg; } for my $table_name (qw(user db tables_priv columns_priv)) { my $frm = "$sandbox_directory/data/mysql/$table_name.frm"; my $myd = "$sandbox_directory/data/mysql/$table_name.MYD"; if ( (-f $frm ) or ( -f $myd) ) { # do nothing print "Table $table_name found\n" if $DEBUG; } else { die "table $table_name not installed\n"; } } for my $logfile (qw(ib_logfile0 ib_logfile1)) { if ( -f "$sandbox_directory/data/$logfile") { unlink "$sandbox_directory/data/$logfile"; } } } else { if ( -e $script ) { die "$script is not executable\n"; } die "$script not found\n"; } } elsif ($msb->{options}{datadir_from} =~ /dir: (.+) /x ) { my $origin = $1; if (-d $origin ) { if ( -f sprintf '%s/mysql/user.MYD', $origin) { my $sandbox_datadir = sprintf '%s/data', $sandbox_directory; if (-d $sandbox_datadir) { if ($msb->{options}{'force'}) { warn "directory $sandbox_datadir already exists. Overwriting its contents\n" if $DEBUG; } else { die "directory $sandbox_datadir already exists. Option --force not specified. Installation halted\n" } } else { mkdir $sandbox_datadir or die "error creating $sandbox_datadir ($!)\n"; } system sprintf 'cp %s %s/* %s/', $msb->{options}{'verbose'} ? q{-vr} : q{-r}, $origin, $sandbox_datadir; } else { die "mysql user table not found in $origin\n"; } } else { die "directory $origin not found\n"; } } else { die "unrecognized value for option 'datadir_from' ($msb->{options}{datadir_from})\n"; } if ($msb->{options}{fix_server_uuid} && ( ! $msb->{options}{keep_uuid})) { if ( $DEBUG ) { print Dumper $msb->{options}{fix_server_uuid}; } fix_server_uuid( @{ $msb->{options}{fix_server_uuid} } ); } if ($msb->{options}{load_grants}) { print "loading grants\n"; system "$sandbox_directory/start" and die "can't start server\n"; # sleep command replaced by internal timeout in the "start" script # sleep 3; system "$sandbox_directory/load_grants" and die "can't load grants\n"; if ($msb->{options}{master}) { system "$sandbox_directory/use -e 'reset master'"; } if ($msb->{options}{slaveof}) { my $cmt = 'CHANGE MASTER TO '; my %cmt_clauses = ( master_host => '127.0.0.1', master_port => undef, master_user => 'rsandbox', master_password => 'rsandbox', master_log_file => undef, master_log_pos => undef, ); my %apply_clauses = map { $_,$cmt_clauses{$_} } grep { $cmt_clauses{$_} } keys %cmt_clauses; for my $clause ( keys %cmt_clauses) { if ($msb->{options}{slaveof} =~ /$clause\s*=([^,]+)/i) { $apply_clauses{$clause}=$1; } } my $count =0; for my $clause (keys %apply_clauses) { if ($count) { $cmt .= ','; } else { $count++; } $cmt .= ' ' . $clause . '=' . quote_clause($apply_clauses{$clause}); } if ($apply_clauses{master_port}) { system "$sandbox_directory/use -e '$cmt; start slave'"; } } if ($msb->{options}{no_run}) { print "stopping server\n"; system "$sandbox_directory/stop" and die "can't stop server\n"; } } print # "installation options saved to current_options.conf.\n", #"To repeat this installation with the same options,\n", #"use $PROGRAM_NAME --conf_file=current_options.conf\n", #('-' x 40), "\n", "Your sandbox server was installed in ", use_env($sandbox_directory), "\n"; sbinstr( "sandbox installed in " . use_env($sandbox_directory)); sub quote_clause { my ($string) = @_; if ($string =~ /^\d+$/) { return $string; } if ($string =~ /^["'].*['"]$/) { return $string; } return qq("$string"); } sub copy_and_replace { my ($filename, $destination_dir, $destination_filename) = @_ ; $destination_filename = $filename unless $destination_filename; my $newname = sprintf('%s/%s', $destination_dir, $destination_filename); #unless ( $scripts_in_code{$filename} ) { # $scripts_in_code{$filename} = ''; # unless ( -f $filename) { # $filename = "$install_dir/$filename"; # } # open my $FROM, q{<}, $filename # or die "error opening $filename ($ERRNO)\n"; # while (<$FROM>) { # for my $key ( keys %replace_options) { # s/ $key /$msb->{options}{$replace_options{$key}}/xg; # } # $scripts_in_code{$filename} .= $_ ; # } # close $FROM; #} open my $TO, q{>}, $newname or die "error creating $newname ($ERRNO)\n"; print "copying $filename into $destination_dir\n" if $DEBUG; my $script_content = $scripts_in_code{$filename} or die "invalid script content for <$filename>\n"; $script_content =~ s/__LICENSE__/$license_text/; my $SBINSTR_SH_TEXT = $MySQL::Sandbox::SBINSTR_SH_TEXT; $script_content =~ s/__SBINSTR_SH__/$SBINSTR_SH_TEXT/; for my $key ( keys %replace_options) { my $new_value = $msb->{options}{$replace_options{$key}}; if ( ($key eq '_DBUSER_') and ($destination_filename =~ /my\.sandbox.cnf/)) { $new_value =~ s/\@.*//g; } unless (defined $new_value) { die "can't find a value for '$key'\n"; } $script_content =~ s/ $key /$new_value/xg; } print $TO $script_content; close $TO; if ($newname =~ / \. (?: sh | pl ) $ /x) { print "changing attributes to $newname\n" if $DEBUG; chmod 0755, $newname; ## no critic my $better_name = $newname; $better_name =~ s/\.(?:sh|pl)$//; rename $newname, $better_name; } elsif ($newname =~ /\.json$/ ) { print "#validating $newname for JSON contents\n" if $DEBUG; my $is_json = MySQL::Sandbox::validate_json_object($newname); if ($is_json && ($is_json == -1)) { warn "Can't validate JSON in $newname\n" if $DEBUG; } elsif (! $is_json) { warn "# JSON object inside newname is not valid\n"; } } return; } sub get_more_options { my ($fname) = @_; my $text = qq(#\n# additional options from $fname \n#\n); open my $MYFILE, q{<}, $fname or die "can't open $fname ($!)\n"; my $start = 0; while (<$MYFILE>) { if ($start ) { last if m/ ^ \s* \[ /x; my ($var) = m/^ \s* (\S+) \s* = /x; next if ( $var && exists ($skip_options{$var} )); $text .= $_; } else { $start = m/ ^ \[mysqld\] /x; } } close $MYFILE; return $text; } sub select_interactively { print "Enter the values for each option\n", "* To leave the interactive choice and accept default values \n", " for the remaining options, enter 'default'\n", "* To go to the previous item, enter 'back'\n", "* To quit the installation without any action, enter 'quit'\n\n"; my @options_list = sort { $msb->{parse_options}{$a}{'so'} <=> $msb->{parse_options}{$b}{'so'} } grep { $_ !~ /(?:interactive|help|no_check_port|no_load_grants)/} grep { $msb->{parse_options}{$_}{'parse'}} keys %{$msb->{parse_options}} ; my $opnum =0; OPTION_CHOICE: while( $opnum < @options_list ) { my $op = $options_list[$opnum]; my $original_default = $msb->{options}{$op} ; my $default = $original_default; $default = $msb->{parse_options}{$op}{'value'} unless defined $default; my $is_array = 0; if (ref($default) && ref($default) eq 'ARRAY') { $default = join(q{ ; } , @{$default}); $is_array=1; } my $chosen = q{}; my ($number_wanted) = $msb->{parse_options}{$op}{'parse'} =~ m/ = (i) /x; print q{-} x 65; print "\n$op\n"; my $text_items = $msb->{parse_options}{$op}{help}; for my $titem (@{$text_items}) { print " $titem \n" if $titem; } print "Your choice: (current value [$default]) "; if ($is_array) { print "(You can enter multiple values separated by ';') "; } $chosen = <>; chomp($chosen); if ($chosen eq 'quit') { exit; } elsif ($chosen eq 'back') { $opnum--; if ($opnum < 0 ) { $opnum = 0; } redo OPTION_CHOICE; } elsif ($chosen eq 'default') { last; } elsif ($chosen =~ m/ ^ \s* $ /x) { $msb->{options}{$op} = $original_default; } elsif ($number_wanted) { if ($chosen =~ m/ ^ \d+ $ /x ) { $msb->{options}{$op} = $chosen; } else { print q{*} x 65, "\n" , "**** option $op requires a numeric value\n" , q{*} x 65, "\n"; redo OPTION_CHOICE; } } else { if($is_array){ $msb->{options}{$op} = [ split /\s*;\s*/, $chosen ] ; } else { $msb->{options}{$op} = $chosen; } } $opnum++; } return; } sub check_sandbox_dir { my $sandboxdir = $ENV{'SANDBOX_HOME'} || "$ENV{'HOME'}/sandboxes"; if (! -d $sandboxdir) { mkdir $sandboxdir; if ( $CHILD_ERROR) { die ("can't set sandbox directory $sandboxdir ($CHILD_ERROR)\n"); } } } sub check_tmp_dir { my $tmpdir = $ENV{'TMPDIR'} || $ENV{'TEMPDIR'}; # print ">>$tmpdir\n"; if (! -d $tmpdir) { die ("can't find tmp directory $tmpdir\n"); } } sub set_sandbox_dir_scripts { my $sandboxdir = $ENV{'SANDBOX_HOME'} or return; if ( $ENV{'SANDBOX_HOME'} eq $ENV{'HOME'} ) { return; } copy_and_replace('sandbox_action.pl', $sandboxdir); copy_and_replace('test_replication.sh', $sandboxdir); copy_and_replace('plugin.conf', $sandboxdir); for my $name (qw(start stop clear use send_kill restart status )) { open my $FH, q{>}, "$sandboxdir/${name}_all" or die "can't create ${name}_all in $sandboxdir\n"; print $FH "#!$msb->{options}{'binbash'}\n"; print $FH qq($sandboxdir/sandbox_action $name "\$\@"\n); close $FH; chmod 0755, "$sandboxdir/${name}_all"; } } MySQL-Sandbox-3.1.04/bin/make_multiple_custom_sandbox000755 000765 000024 00000020751 12566053633 022713 0ustar00gmaxstaff000000 000000 #!/usr/bin/perl # make_multiple_custom_sandbox # The MySQL Sandbox # Copyright (C) 2006-2015 Giuseppe Maxia # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. use strict; use warnings; use English qw( -no_match_vars ); use Data::Dumper; use Getopt::Long qw(:config no_ignore_case ); use MySQL::Sandbox qw(get_ranges runs_as_root use_env sbinstr); use MySQL::Sandbox::Scripts; my $DEBUG = $MySQL::Sandbox::DEBUG; runs_as_root(); my %defaults = ( custom_base_port => $MySQL::Sandbox::default_base_port{custom}, group_directory => 'multi_cmsb', ); unless ( -d $ENV{'SANDBOX_HOME'} ) { mkdir $ENV{'SANDBOX_HOME'} or die "can't create $ENV{'SANDBOX_HOME'} ($CHILD_ERROR) \n"; } #my $install_dir; #$install_dir = $PROGRAM_NAME; #$install_dir =~ s{/\w+(\.pl)?$}{}; #eval "use lib q($install_dir)"; #eval "use MySandbox"; #eval "use MyScripts"; my $msb = MySQL::Sandbox->new(); $msb->parse_options (MySQL::Sandbox::Scripts::parse_options_many() ); GetOptions ( map { $msb->{parse_options}{$_}{parse}, \$msb->{options}{$_} } grep { $msb->{parse_options}{$_}{parse}} keys %{$msb->{parse_options}} ) or $msb->get_help(); $msb->get_help() if $msb->{options}{'help'}; unless ($msb->{options}{server_version}) { $msb->{options}{server_version} = join(':', @ARGV); @ARGV > 0 or $msb->get_help('server version required'); } if ($msb->{options}{node_options}) { $ENV{NODE_OPTIONS} = $msb->{options}{node_options}; } if ($msb->{options}{one_node_options}) { for my $node_opt (@{ $msb->{options}{one_node_options}} ) { if ($node_opt =~ /^(\d+):\s*(\S.+)/) { $ENV{"NODE${1}_OPTIONS"} = $2; } else { get_help("invalid format for --one_node_option ($node_opt)"); } } } my $replication_port = 0; my @base_version ; my @dashed_version ; my @versions= split /[,:;]/, $msb->{options}{server_version}; my $counter =0; for my $ver (@versions) { my $temp_path = $ver; $temp_path =~ s{.*/}{}; my $prefix =''; if ( $temp_path =~ /^(\D+)\d+/ ) { $prefix = $1; } if ( $temp_path =~ /(\d+)\.(\d+)\.(\d+)/ ) { $base_version[$counter] = "$1$2$3"; $dashed_version[$counter] = "${prefix}$1_$2_$3"; $base_version[$counter] =~ s/^0+//; $counter++; } else { $msb->get_help("No recognizable version pattern in $msb->{options}{server_version}\n"); } } my $group_directory ; if ( $msb->{options}{group_directory}) { $group_directory = "$msb->{options}{upper_directory}/$msb->{options}{group_directory}"; } else { $group_directory = "$msb->{options}{upper_directory}/" . make_group_dir( $defaults{group_directory}, \@dashed_version); } if ( -d $group_directory ) { system "$group_directory/clear_all"; } else { print "creating replication directory $group_directory\n" if $msb->{options}{verbose}; mkdir $group_directory or die "can't create $group_directory \n"; } for my $dir ( 1 .. @versions ) { if ( -d "$group_directory/node$dir" ) { system "rm -rf $group_directory/node$dir" and die "unable to clean $group_directory/node$dir\n"; } } my $custom_base_port = 0; if ( $msb->{options}{sandbox_base_port}) { $custom_base_port = $msb->{options}{sandbox_base_port}; } else { $custom_base_port = $defaults{custom_base_port}; } if ( $msb->{options}{check_base_port}) { $custom_base_port = get_ranges({ min_range => $custom_base_port, range_size => $#versions, max_range => 64000, search_path => $ENV{SANDBOX_HOME}, }, 1); } for my $ver_counter (0 .. $#versions) { if ( $msb->{options}{sandbox_base_port}) { $replication_port = $custom_base_port; } else { $replication_port = $custom_base_port + $base_version[$ver_counter]; } my $additional_node_options = $ENV{NODE_OPTIONS} || ''; $additional_node_options .= q{ }; my $node = $ver_counter + 1; my $node_port = $replication_port+ $node; print "installing node $node\n"; my $this_node_options = $ENV{"NODE${node}_OPTIONS"} || ''; my $install_node = ''; my $install_node_command = qq( make_sandbox $versions[$ver_counter] -- \\ --datadir_from=script \\ --upper_directory=$group_directory \\ --sandbox_directory=node$node \\ --no_confirm \\ --no_check_port \\ --prompt_prefix=node$node \\ --sandbox_port=$node_port \\ --history_dir=$group_directory \\ -c server-id=10$node \\ -c relay-log-index=mysql-relay \\ -c relay-log=mysql-relay \\ -c log-bin=mysql-bin $additional_node_options ); if ($msb->{options}{interactive} or ($additional_node_options =~ /\binteractive\b/)) { system($install_node_command); } else { $install_node = qx($install_node_command); } print $install_node if $msb->{options}{verbose}; if ($CHILD_ERROR) { print "error installing node $node\n"; print "$install_node\n($CHILD_ERROR $OS_ERROR)\n"; exit(1) } # sleep 1; } my $current_dir = $ENV{PWD}; chdir $group_directory; for my $cmd ( qw(start stop clear send_kill ) ) { my $cmd_fname = $cmd . '_all'; $msb->write_to($cmd_fname, '>', '#!/bin/sh'); $msb->write_to($cmd_fname, '>>', qq(echo '# executing "$cmd"' on $group_directory)); for my $node (1 .. @versions ) { $msb->write_to ($cmd_fname, '>>', qq(echo 'executing "$cmd" on node $node')); $msb->write_to ($cmd_fname, '>>', qq($group_directory/node$node/$cmd "\$@")); } chmod 0755, $cmd_fname; } $msb->write_to('restart_all', '>', '#!/bin/sh'); $msb->write_to('restart_all', '>>', qq($group_directory/stop_all)); $msb->write_to('restart_all', '>>', qq($group_directory/start_all "\$@")); chmod 0755, 'restart_all'; $msb->write_to('use_all', '>', '#!/bin/sh'); my $node_list = join(' ', (1 .. @versions ) ); $msb->write_to('use_all', '>>', 'if [ "$1" = "" ]'); $msb->write_to('use_all', '>>', 'then'); $msb->write_to('use_all', '>>', ' echo "syntax: $0 command"'); $msb->write_to('use_all', '>>', ' exit 1'); $msb->write_to('use_all', '>>', 'fi'); $msb->write_to('use_all', '>>', ''); $msb->write_to('use_all', '>>', 'for SNUM in ' . $node_list); $msb->write_to('use_all', '>>', 'do ' ); $msb->write_to('use_all', '>>', ' echo "# server: $SNUM " ' ); $msb->write_to('use_all', '>>', ' echo "$@" | ' . $group_directory . '/node$SNUM/use $MYCLIENT_OPTIONS '); $msb->write_to('use_all', '>>', 'done ' ); chmod 0755, 'use_all'; $msb->write_to('status_all', '>', '#!/bin/sh'); my $gdir = $group_directory; $gdir =~ s{.*/}{}; $msb->write_to('status_all', '>>', "echo CUSTOM $gdir" ); $msb->write_to('status_all', '>>', 'for SNUM in ' . $node_list); $msb->write_to('status_all', '>>', 'do ' ); $msb->write_to('status_all', '>>', $group_directory . '/node$SNUM/status'); $msb->write_to('status_all', '>>', 'done ' ); chmod 0755, 'status_all'; for my $node (1 .. @versions ) { $msb->write_to("n$node", '>', "#!/bin/sh"); $msb->write_to("n$node", '>', qq($group_directory/node$node/use "\$@")); chmod 0755, "n$node"; } my @nodes ; for my $N (1 .. $msb->{options}{how_many_nodes}) { push @nodes, "node$N"; } for my $json (qw(connection.json default_connection.json)) { my $json_text = MySQL::Sandbox::get_json_from_dirs(\@nodes, $json); $msb->write_to($json, '>', $json_text); } $msb->write_to('README', '>', MySQL::Sandbox::Scripts::get_readme_multiple()); $msb->write_to('README', '>', MySQL::Sandbox::Scripts::get_readme_common()); chdir $current_dir; print "group directory installed in ", use_env($group_directory),"\n"; sbinstr( "group_directory installed in <" . use_env($group_directory) . ">"); sub make_group_dir { my ($base_dir, $dashed) = @_; my @copy_dashed = @$dashed; my $suffix = ''; if (@copy_dashed > 3) { $suffix = join('-', map { s/(\d+_\d+).*/$1/; $_ } @copy_dashed ); } else { $suffix = join('-', @$dashed); } return $base_dir . '_' . $suffix; } __END__ MySQL-Sandbox-3.1.04/bin/make_multiple_sandbox000755 000765 000024 00000032713 12576721401 021316 0ustar00gmaxstaff000000 000000 #!/usr/bin/perl # make_multiple_sandbox # The MySQL Sandbox # Copyright (C) 2006-2015 Giuseppe Maxia # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. use strict; use warnings; use English qw( -no_match_vars ); use Data::Dumper; use Getopt::Long qw(:config no_ignore_case ); use MySQL::Sandbox qw(get_ranges runs_as_root use_env sbinstr); use MySQL::Sandbox::Scripts; my $DEBUG = $MySQL::Sandbox::DEBUG; runs_as_root(); unless ( -d $ENV{'SANDBOX_HOME'} ) { mkdir $ENV{'SANDBOX_HOME'} or die "can't create $ENV{'SANDBOX_HOME'} ($CHILD_ERROR) \n"; } #my $install_dir; #$install_dir = $PROGRAM_NAME; #$install_dir =~ s{/\w+(\.pl)?$}{}; #eval "use lib q($install_dir)"; #eval "use MySandbox"; #eval "use MyScripts"; my $msb = MySQL::Sandbox->new(); my %defaults = ( circular_base_port => $MySQL::Sandbox::default_base_port{multiple},, group_directory => 'multi_msb', ); $msb->parse_options ( MySQL::Sandbox::Scripts::parse_options_many() ); # my %{$msb->{options}} = map { $_ , $msb->{parse_options}{$_}{'value'}} keys %{$msb->{parse_options}} ; GetOptions ( map { $msb->{parse_options}{$_}{parse}, \$msb->{options}{$_} } grep { $msb->{parse_options}{$_}{parse}} keys %{$msb->{parse_options}} ) or $msb->get_help(); $msb->get_help() if $msb->{options}{'help'}; unless ($msb->{options}{server_version}) { $msb->{options}{server_version} = shift or $msb->get_help('server version required'); } for my $opt (qw(repl_user repl_password remote_access)) { if (defined $msb->{options}{$opt}) { $MySQL::Sandbox::default_users{$opt} = $msb->{options}{$opt}; } } if ($msb->{options}{node_options}) { $ENV{NODE_OPTIONS} = $msb->{options}{node_options}; } if ($msb->{options}{one_node_options}) { for my $node_opt (@{ $msb->{options}{one_node_options}} ) { if ($node_opt =~ /^(\d+):\s*(\S.+)/) { $ENV{"NODE${1}_OPTIONS"} = $2; } else { get_help("invalid format for --one_node_option ($node_opt)"); } } } my $base_version ; my $release_no; my $dashed_version ; my $replication_port = 0; my $temp_path = $msb->{options}{server_version}; $temp_path =~ s{.*/}{}; my $prefix = ''; if ( $temp_path =~ /^(\D+)\d+/ ) { $prefix = $1; } if ( $temp_path =~ /(\d+)\.(\d+)\.(\d+)/ ) { $base_version = "$1$2$3"; $release_no = $3; $dashed_version = "${prefix}$1_$2_$3"; $base_version =~ s/^0+//; } else { $msb->get_help("No recognizable version pattern in $msb->{options}{server_version}\n"); } #print Dumper(\%{$msb->{options}}); my $group_directory ; if ( $msb->{options}{group_directory}) { $group_directory = "$msb->{options}{upper_directory}/$msb->{options}{group_directory}"; } else { $group_directory = "$msb->{options}{upper_directory}/$defaults{group_directory}_$dashed_version"; } if ( -d $group_directory ) { if ( -x "$group_directory/clear_all" ) { system "$group_directory/clear_all"; } system "rm -rf $group_directory/*"; } else { print "creating group directory $group_directory\n" if $msb->{options}{verbose}; mkdir $group_directory or die "can't create $group_directory\n"; } if ( -f "$group_directory/needs_initialization" ) { system "rm -f $group_directory/needs_initialization" ; } if ($msb->{options}{'master_master'}) { $msb->{options}{'how_many_nodes'} = 2; $msb->{options}{'circular'} = 1; } for my $dir ( 1 .. $msb->{options}{how_many_nodes}) { if ( -d "$group_directory/node$dir" ) { system "rm -rf $group_directory/node$dir" and die "unable to clean $group_directory/node$dir\n"; } } if ( $msb->{options}{sandbox_base_port}) { $replication_port = $msb->{options}{sandbox_base_port}; } else { $replication_port = $defaults{circular_base_port} + $base_version + ($release_no * 100); } if ( $msb->{options}{check_base_port}) { $replication_port = get_ranges({ min_range => $replication_port, range_size => $msb->{options}{how_many_nodes}, max_range => 64000, search_path => $ENV{SANDBOX_HOME}, }, 1); } my $circular_replication_script = "$group_directory/set_circular_replication.sh"; if ($msb->{options}{'circular'}) { $msb->write_to($circular_replication_script, '>', qq( #!/bin/bash TMPL1="change master to master_host='127.0.0.1'," TMPL2="master_user='$MySQL::Sandbox::default_users{'repl_user'}'," TMPL3="master_password='$MySQL::Sandbox::default_users{'repl_password'}'," TMPL4="master_port" TMPL="\$TMPL1 \$TMPL2 \$TMPL3 \$TMPL4" )); $msb->write_to($circular_replication_script, '>>', "$group_directory/use_all 'reset master' "); $msb->write_to($circular_replication_script, '>>', "$group_directory/use_all 'stop slave' "); } for my $node (1 .. $msb->{options}{how_many_nodes}) { my $additional_node_options = $ENV{NODE_OPTIONS} || ''; my $this_node_options = $ENV{"NODE${node}_OPTIONS"} || ''; my $node_port = $replication_port+ $node; if ($msb->{options}{'circular'}) { my $master_node_port = $node == 1 ? $node_port + $msb->{options}{how_many_nodes} -1 : $node_port -1; $additional_node_options .= '-c log-slave-updates ' . '-c replicate-same-server-id=0 ' . '-c auto_increment_increment=' . $msb->{options}{'how_many_nodes'} . ' ' . '-c auto_increment_offset=' . $node . ' ' . '-c report-host=SBnode' . $node . ' ' . "-c report-port=$node_port" ; } $additional_node_options .= q{ }; my $node_id = 100 + $node; print "installing node $node\n"; my $install_node = ''; my $install_node_command = qq( make_sandbox $msb->{options}{server_version} -- \\ --datadir_from=script \\ --upper_directory=$group_directory \\ --sandbox_directory=node$node \\ --history_dir=$group_directory \\ --no_confirm \\ --no_check_port \\ --repl_user=$msb->{options}{repl_user} \\ --repl_password=$msb->{options}{repl_password} \\ --remote_access=$msb->{options}{remote_access} \\ --prompt_prefix=node$node \\ --sandbox_port=$node_port \\ -c server-id=$node_id \\ -c relay-log-index=mysql-relay \\ -c relay-log=mysql-relay \\ -c log-bin=mysql-bin $additional_node_options $this_node_options ); if ($msb->{options}{interactive} or ($additional_node_options =~ /\binteractive\b/)) { system($install_node_command); } else { $install_node = qx($install_node_command); } print $install_node if $msb->{options}{verbose}; if ($CHILD_ERROR) { print "error installing node $node\n"; print "$install_node\n($CHILD_ERROR $OS_ERROR)\n"; exit(1) } #sleep 1; if ($msb->{options}{'circular'}) { my $master_node = $node + 1 ; if ($master_node > $msb->{options}{'how_many_nodes'} ) { $master_node = 1; } $msb->write_to($circular_replication_script, '>>', sprintf(q(echo "$TMPL=%d" | %s/node%d/use -u root ), $node_port, $group_directory, $master_node ) ); } } if ($msb->{options}{'circular'}) { $msb->write_to($circular_replication_script, '>>', "$group_directory/use_all 'start slave' "); chmod 0755, $circular_replication_script; } my $current_dir = $ENV{PWD}; chdir $group_directory; for my $cmd ( qw(start stop clear send_kill ) ) { my $cmd_fname = $cmd . '_all'; $msb->write_to($cmd_fname, '>', '#!/bin/sh'); $msb->write_to($cmd_fname, '>>', qq(echo '# executing "$cmd"' on $group_directory)); if ($cmd =~ /stop|clear|send_kill/ && $msb->{options}{'circular'}) { $msb->write_to ($cmd_fname, '>>', qq($group_directory/use_all "stop slave")); } for my $node (1 .. $msb->{options}{how_many_nodes} ) { $msb->write_to ($cmd_fname, '>>', qq(echo 'executing "$cmd" on node $node')); $msb->write_to ($cmd_fname, '>>', qq($group_directory/node$node/$cmd "\$@")); if (($cmd eq 'start') and $msb->{options}{'circular'}) { $msb->write_to ($cmd_fname, '>>', "if [ -f $group_directory/node$node/data/master.info ] \n" . "then\n" . " echo 'stop slave' | $group_directory/n$node -u root\n" . "fi"); } } chmod 0755, $cmd_fname; } $msb->write_to('restart_all', '>', '#!/bin/sh'); $msb->write_to('restart_all', '>>', qq($group_directory/stop_all)); $msb->write_to('restart_all', '>>', qq($group_directory/start_all "\$@")); chmod 0755, 'restart_all'; $msb->write_to('use_all', '>', '#!/bin/sh'); my $node_list = join(' ', (1 .. $msb->{options}{how_many_nodes}) ); $msb->write_to('use_all', '>>', 'if [ "$1 " = " " ]'); $msb->write_to('use_all', '>>', 'then'); $msb->write_to('use_all', '>>', ' echo "syntax: $0 command"'); $msb->write_to('use_all', '>>', ' exit 1'); $msb->write_to('use_all', '>>', 'fi'); $msb->write_to('use_all', '>>', ''); $msb->write_to('use_all', '>>', 'for SNUM in ' . $node_list); $msb->write_to('use_all', '>>', 'do ' ); $msb->write_to('use_all', '>>', ' echo "# server: $SNUM: " ' ); $msb->write_to('use_all', '>>', ' echo "$@" | ' . $group_directory . '/node$SNUM/use $MYCLIENT_OPTIONS '); $msb->write_to('use_all', '>>', 'done ' ); chmod 0755, 'use_all'; $msb->write_to('status_all', '>', '#!/bin/sh'); my $gdir = $group_directory; $gdir =~ s{.*/}{}; my $group_type = 'MULTIPLE'; if ($msb->{options}{'circular'}) { $group_type = 'CIRC-REPL'; } $msb->write_to('status_all', '>>', "echo $group_type $gdir" ); $msb->write_to('status_all', '>>', 'for SNUM in ' . $node_list); $msb->write_to('status_all', '>>', 'do ' ); $msb->write_to('status_all', '>>', ' ' . $group_directory . '/node$SNUM/status'); $msb->write_to('status_all', '>>', ' ' . $group_directory . '/node$SNUM/use -BN -e' . qq( "select CONCAT('port: ', \@\@port) AS port" )); $msb->write_to('status_all', '>>', 'done ' ); chmod 0755, 'status_all'; $msb->write_to('check_slaves', '>', '#!/bin/sh' ); $msb->write_to('check_slaves', '>>', 'for NNUM in ' . $node_list ); $msb->write_to('check_slaves', '>>', 'do' ); $msb->write_to('check_slaves', '>>', ' echo "node # $NNUM"'); $msb->write_to('check_slaves', '>>', ' ' . $group_directory . '/node$NNUM/use -BN -e' . qq( "select CONCAT('port: ', \@\@port) AS port" )); $msb->write_to('check_slaves', '>>', " $group_directory/node\$NNUM/use -e " . qq( 'show master status\\G' | grep "File\\|Position" )); $msb->write_to('check_slaves', '>>', ' echo "" ' ); $msb->write_to('check_slaves', '>>', " $group_directory/node\$NNUM/use -e " . qq( 'show slave status\\G' | grep "\\(Running:\\|Master_Log_Pos\\|\\write_to('check_slaves', '>>', 'done ' ); chmod 0755, 'check_slaves'; for my $node (1 .. $msb->{options}{how_many_nodes} ) { $msb->write_to("n$node", '>', "#!/bin/sh"); $msb->write_to("n$node", '>', qq($group_directory/node$node/use "\$@")); chmod 0755, "n$node"; } if ($msb->{options}{'circular'}) { $msb->write_to( "$group_directory/clear_all", '>>', "date > $group_directory/needs_initialization"); $msb->write_to(qq($group_directory/start_all), '>>', "if [ -f $group_directory/needs_initialization ] \n" . "then\n" . " $circular_replication_script\n" . " rm -f $group_directory/needs_initialization\n" . "else\n" . " $group_directory/use_all 'start slave' \n" . "fi"); # # Creates the replication user in all nodes # ## system qq( MYCLIENT_OPTIONS='-u root' ./use_all 'grant replication slave on *.* ) ## . qq( to "$MySQL::Sandbox::default_users{'repl_user'}"\@"127.%" ) . ## . qq(identified by "$MySQL::Sandbox::default_users{'repl_password'}"') ## and die "can't create slave user"; my $result = system($circular_replication_script); if ($result) { die ("error starting up circular replication ($!)\n"); } else { print "Circular replication activated\n"; } } my @nodes ; for my $N (1 .. $msb->{options}{how_many_nodes}) { push @nodes, "node$N"; } for my $json (qw(connection.json default_connection.json)) { my $json_text = MySQL::Sandbox::get_json_from_dirs(\@nodes, $json); $msb->write_to($json, '>', $json_text); } if ($msb->{options}{circular}) { $msb->write_to('README', '>', MySQL::Sandbox::Scripts::get_readme_circular()); $msb->write_to('README', '>>', MySQL::Sandbox::Scripts::get_readme_common_replication()); } else { $msb->write_to('README', '>', MySQL::Sandbox::Scripts::get_readme_multiple()); } $msb->write_to('README', '>>', MySQL::Sandbox::Scripts::get_readme_common()); chdir $current_dir; print "group directory installed in ", use_env($group_directory),"\n"; sbinstr( "group_directory installed in <" . use_env($group_directory) . ">"); __END__ MySQL-Sandbox-3.1.04/bin/make_replication_sandbox000755 000765 000024 00000052711 12576721401 021774 0ustar00gmaxstaff000000 000000 #!/usr/bin/perl # make_replication_sandbox # The MySQL Sandbox # Copyright (C) 2006-2015 Giuseppe Maxia # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. use strict; use warnings; use English qw( -no_match_vars ); use Data::Dumper; use Getopt::Long qw(:config no_ignore_case ); use MySQL::Sandbox qw(get_ranges runs_as_root use_env sbinstr); use MySQL::Sandbox::Scripts; my $DEBUG = $MySQL::Sandbox::DEBUG; runs_as_root(); my %defaults = ( replication_base_port => $MySQL::Sandbox::default_base_port{replication}, circular_base_port => $MySQL::Sandbox::default_base_port{circular}, replication_directory => 'rsandbox', ); unless ( $ENV{SANDBOX_HOME} ) { $ENV{SANDBOX_HOME} = "$ENV{HOME}/sandboxes"; } # # $SANDBOX_HOME must be set BEFORE loading MyScripts # #if ( -d "$ENV{HOME}/sandboxes" ) { # $ENV{SANDBOX_HOME} = $ENV{SANDBOX_HOME} || "$ENV{HOME}/sandboxes"; #} # unless ( -d $ENV{'SANDBOX_HOME'} ) { mkdir $ENV{'SANDBOX_HOME'} or die "can't create $ENV{'SANDBOX_HOME'} ($CHILD_ERROR) \n"; } #my $install_dir; #$install_dir = $PROGRAM_NAME; #$install_dir =~ s{/\w+(\.pl)?$}{}; # eval "use lib q($install_dir)"; my $msb = MySQL::Sandbox->new(); $msb->parse_options( MySQL::Sandbox::Scripts::parse_options_replication() ); GetOptions ( map { $msb->{parse_options}{$_}{parse}, \$msb->{options}{$_} } grep { $msb->{parse_options}{$_}{parse}} keys %{$msb->{parse_options}} ) or $msb->get_help(); $msb->get_help() if $msb->{options}{'help'}; unless ($msb->{options}{server_version}) { $msb->{options}{server_version} = shift or $msb->get_help('server version required'); } if ($msb->{options}{master_options}) { $ENV{MASTER_OPTIONS} = $msb->{options}{master_options}; } if ($msb->{options}{node_options}) { $ENV{NODE_OPTIONS} = $msb->{options}{node_options}; } if ($msb->{options}{slave_options}) { $ENV{SLAVE_OPTIONS} = $msb->{options}{slave_options}; } if ($msb->{options}{one_node_options}) { for my $node_opt (@{ $msb->{options}{one_node_options}} ) { if ($node_opt =~ /^(\d+):\s*(\S.+)/) { $ENV{"NODE${1}_OPTIONS"} = $2; } else { get_help("invalid format for --one_node_option ($node_opt)"); } } } if ($msb->{options}{one_slave_options}) { for my $node_opt (@{ $msb->{options}{one_slave_options}} ) { if ($node_opt =~ /^(\d+):\s*(\S.+)/) { $ENV{"SLAVE${1}_OPTIONS"} = $2; } else { get_help("invalid format for --one_slave_option ($node_opt)"); } } } for my $opt (qw(repl_user repl_password remote_access)) { if (defined $msb->{options}{$opt}) { $MySQL::Sandbox::default_users{$opt} = $msb->{options}{$opt}; } } my $base_version ; my $release_no; my $create_gtid_script=0; my $master_use_gtid=0; my $dashed_version ; my $replication_port = 0; my $prefix=''; my $additional_master_options = $ENV{MASTER_OPTIONS} || ''; my $temp_path = $msb->{options}{server_version}; $temp_path =~ s{.*/}{}; if ( $temp_path =~ /^(\D+)\d+/ ) { $prefix = $1; } if ( $temp_path =~ /(\d+)\.(\d+)\.(\d+)/ ) { my ($major, $minor, $rev) = ($1, $2, $3); $base_version = "${major}${minor}${rev}"; $release_no = $rev; $dashed_version = "${prefix}${major}_${minor}_${rev}"; $base_version =~ s/^0+//; $base_version += $major + ($minor * 10) + ($rev * 100); if ( ($major > 5) # MySQL 6 or (($major == 5) && ($minor == 6) && ($rev >= 9 )) #MySQL 5.6.9 and newer or (( $major == 5) && ($minor > 6)) # MySQL 5.7 and newer ) { $create_gtid_script=1; } if ($create_gtid_script && ($major == 10)) { $create_gtid_script =0; $master_use_gtid=1; } } else { $msb->get_help("No recognizable version pattern in $msb->{options}{server_version}\n"); } my @supported_topologies = qw(standard circular); # # deals with circular replication # my $node_list_text = 'master'; my @node_list = ('master'); if ($msb->{options}{master_master}) { $msb->{options}{topology} = 'circular'; $msb->{options}{how_many_slaves} = 2; } if ($msb->{options}{circular} && ($msb->{options}{circular} =~ /^\d+$/)) { $msb->{options}{topology} = 'circular'; $msb->{options}{how_many_slaves} = $msb->{options}{circular}; } if ($msb->{options}{topology} eq 'circular') { $node_list_text = ''; @node_list = (); } for my $n (1 .. $msb->{options}{how_many_slaves}) { $node_list_text .= " node$n"; push @node_list, "node$n"; } if ($msb->{options}{'topology'} ) { if ($msb->{options}{'topology'} eq 'standard') { # do nothing. default behavior } elsif ($msb->{options}{'topology'} eq 'circular') { make_circular_replication(); } else { die qq(unsupported topology "$msb->{options}{topology}". Allowed options: {@supported_topologies}\n); } } # print Dumper(\%{$msb->{options}}); my $replication_directory ; if ( $msb->{options}{replication_directory}) { $replication_directory = "$msb->{options}{upper_directory}/$msb->{options}{replication_directory}"; } else { $replication_directory = "$msb->{options}{upper_directory}/$defaults{replication_directory}_$dashed_version"; } if ( -d $replication_directory ) { if ( -x "$replication_directory/clear_all") { system "$replication_directory/clear_all"; } system "rm -rf $replication_directory/*"; } else { print "creating replication directory $replication_directory\n" if $msb->{options}{verbose}; mkdir $replication_directory; unless ( -d $replication_directory ) { die "error creating replication directory n"; } } for my $dir ( 1 .. $msb->{options}{how_many_slaves}) { if ( -d "$replication_directory/node$dir" ) { system "rm -rf $replication_directory/node$dir" and die "unable to clean $replication_directory/node$dir\n"; } } if ( -d "$replication_directory/master" ) { system "rm -rf $replication_directory/master" and die "unable to clean $replication_directory/master\n"; } if ( $msb->{options}{sandbox_base_port}) { $replication_port = $msb->{options}{sandbox_base_port}; } else { $replication_port = $defaults{replication_base_port} + $base_version + ($release_no * 100); } if ( $msb->{options}{check_base_port}) { $replication_port = get_ranges({ min_range => $replication_port, range_size => $msb->{options}{how_many_slaves}, max_range => 64000, search_path => $ENV{SANDBOX_HOME}, }, 1); } print "installing and starting master\n"; my $additional_slave_options = $ENV{SLAVE_OPTIONS} || ''; if ($ENV{NODE_OPTIONS}) { $additional_master_options .= q{ } . $ENV{NODE_OPTIONS}; $additional_slave_options .= q{ } . $ENV{NODE_OPTIONS}; } $additional_master_options .= q{ }; $additional_slave_options .= q{ }; my $install_master=''; my $install_master_command = qq( make_sandbox $msb->{options}{server_version} -- \\ --datadir_from=script \\ --no_confirm \\ --no_check_port \\ --upper_directory=$replication_directory \\ --sandbox_directory=master \\ --sandbox_port=$replication_port \\ --repl_user=$msb->{options}{repl_user} \\ --repl_password=$msb->{options}{repl_password} \\ --remote_access=$msb->{options}{remote_access} \\ --load_grants \\ --prompt_prefix=master \\ --history_dir=$replication_directory \\ -c relay-log-index=mysql-relay \\ -c relay-log=mysql-relay \\ -c log-bin=mysql-bin \\ -c server-id=1 $additional_master_options ); if ($msb->{options}{interactive} or ($additional_master_options =~ /\binteractive\b/)) { my $result = system($install_master_command); } else { my $install_master = qx($install_master_command); print $install_master if $msb->{options}{verbose}; } if ($CHILD_ERROR) { print "error installing the master\n"; print "$install_master\n($CHILD_ERROR $OS_ERROR)\n"; exit(1) } # sleep 1 ; for my $slave (1 .. $msb->{options}{how_many_slaves}) { my $slave_port = $replication_port+ $slave; my $slave_id = 100 + $slave; print "installing slave $slave\n"; my $this_slave_options = $ENV{"SLAVE${slave}_OPTIONS"} || ''; my $install_slave_command = qq( make_sandbox $msb->{options}{server_version} -- \\ --datadir_from=script \\ --upper_directory=$replication_directory \\ --sandbox_directory=node$slave \\ --no_confirm \\ --no_load_grants \\ --prompt_prefix=slave$slave \\ --sandbox_port=$slave_port \\ --repl_user=$msb->{options}{repl_user} \\ --repl_password=$msb->{options}{repl_password} \\ --remote_access=$msb->{options}{remote_access} \\ --history_dir=$replication_directory \\ -c server-id=$slave_id \\ -c report-host=SBslave$slave \\ -c report-port=$slave_port \\ -c relay-log-index=mysql-relay \\ -c relay-log=mysql-relay \\ -c log-bin=mysql-bin $additional_slave_options $this_slave_options ); my $install_slave =''; if ($msb->{options}{interactive} or ($additional_slave_options =~ /\binteractive\b/)) { system($install_slave_command); } else { $install_slave = qx($install_slave_command); print $install_slave if $msb->{options}{verbose}; } if ($CHILD_ERROR) { print "error installing slave $slave\n"; print "$install_slave\n ($CHILD_ERROR)\n"; exit(1) } # sleep 1; } my $current_dir = $ENV{PWD}; chdir $replication_directory; for my $cmd ( qw(start stop clear send_kill ) ) { my $cmd_fname = $cmd . '_all'; $msb->write_to($cmd_fname, '>', '#!/bin/sh'); $msb->write_to($cmd_fname, '>>', qq(echo '# executing "$cmd"' on $replication_directory)); if ($cmd eq 'start') { $msb->write_to ($cmd_fname, '>>', qq(echo 'executing "$cmd" on master') ); $msb->write_to ($cmd_fname, '>>', qq($replication_directory/master/$cmd "\$@") ); } for my $slave (1 .. $msb->{options}{how_many_slaves} ) { $msb->write_to ($cmd_fname, '>>', qq(echo 'executing "$cmd" on slave $slave')); $msb->write_to ($cmd_fname, '>>', qq($replication_directory/node$slave/$cmd "\$@")); } if ($cmd ne 'start') { $msb->write_to ($cmd_fname, '>>', qq(echo 'executing "$cmd" on master') ); $msb->write_to ($cmd_fname, '>>', qq($replication_directory/master/$cmd "\$@")); } chmod 0755, $cmd_fname; } my $rw_splitting = '/usr/local/share/mysql-proxy/rw-splitting.lua'; my $mysql_proxy = '/usr/local/sbin/mysql-proxy'; if ( ( -x $mysql_proxy ) && ( -f $rw_splitting) ) { my $port = $replication_port; $msb->write_to('run_proxy', '>', '#!/bin/sh'); $msb->write_to('run_proxy', '>>', "$mysql_proxy \\" ); $msb->write_to('run_proxy', '>>', " --proxy-backend-addresses=127.0.0.1:$port \\" ); for my $slave ( 1 .. $msb->{options}{how_many_slaves}) { $port++; $msb->write_to('run_proxy', '>>', " --proxy-read-only-backend-addresses=127.0.0.1:$port \\" ); } $msb->write_to('run_proxy', '>>', " --proxy-lua-script=$rw_splitting" ); chmod 0755, 'run_proxy'; } $msb->write_to('clear_all', '>>', "date > $replication_directory/needs_initialization"); $msb->write_to('start_all', '>>', "if [ -f $replication_directory/needs_initialization ] "); $msb->write_to('start_all', '>>', "then"); $msb->write_to('start_all', '>>', " $replication_directory/initialize_slaves"); $msb->write_to('start_all', '>>', " rm -f $replication_directory/needs_initialization"); $msb->write_to('start_all', '>>', "fi"); $msb->write_to('m', '>', "#!/bin/sh"); $msb->write_to('m', '>>', qq($replication_directory/master/use "\$@") ); chmod 0755, 'm'; $msb->write_to('restart_all', '>', '#!/bin/sh'); $msb->write_to('restart_all', '>>', qq($replication_directory/stop_all)); $msb->write_to('restart_all', '>>', qq($replication_directory/start_all "\$@")); chmod 0755, 'restart_all'; $msb->write_to('use_all', '>', '#!/bin/sh'); my $slave_list = join(' ', (1 .. $msb->{options}{how_many_slaves}) ); $msb->write_to('use_all', '>>', 'if [ "$1" = "" ]'); $msb->write_to('use_all', '>>', 'then'); $msb->write_to('use_all', '>>', ' echo "syntax: $0 command"'); $msb->write_to('use_all', '>>', ' exit 1'); $msb->write_to('use_all', '>>', 'fi'); $msb->write_to('use_all', '>>', ''); $msb->write_to('use_all', '>>', 'echo "# master " ' ); $msb->write_to('use_all', '>>', 'echo "$@" | ' . $replication_directory . '/master/use '); $msb->write_to('use_all', '>>', ''); $msb->write_to('use_all', '>>', 'for SNUM in ' . $slave_list); $msb->write_to('use_all', '>>', 'do ' ); $msb->write_to('use_all', '>>', ' echo "# server: $SNUM: " ' ); $msb->write_to('use_all', '>>', ' echo "$@" | ' . $replication_directory . '/node$SNUM/use $MYCLIENT_OPTIONS '); $msb->write_to('use_all', '>>', 'done ' ); chmod 0755, 'use_all'; $msb->write_to('status_all', '>', '#!/bin/sh'); my $rdir = $replication_directory; $rdir =~ s{.*/}{}; $msb->write_to('status_all', '>>', "echo REPLICATION $rdir"); $msb->write_to('status_all', '>>', $replication_directory . '/master/status'); $msb->write_to('status_all', '>>', $replication_directory . '/master/use -BN -e' . qq( "select CONCAT('port: ', \@\@port) AS port" )); $msb->write_to('status_all', '>>', ''); $msb->write_to('status_all', '>>', 'for SNUM in ' . $slave_list); $msb->write_to('status_all', '>>', 'do ' ); $msb->write_to('status_all', '>>', ' ' . $replication_directory . '/node$SNUM/status'); $msb->write_to('status_all', '>>', ' ' . $replication_directory . '/node$SNUM/use -BN -e' . qq( "select CONCAT('port: ', \@\@port) AS port" )); $msb->write_to('status_all', '>>', 'done ' ); chmod 0755, 'status_all'; $msb->write_to('check_slaves', '>', '#!/bin/sh' ); $msb->write_to('check_slaves', '>>', 'echo "master"'); $msb->write_to('check_slaves', '>>', $replication_directory . '/master/use -BN -e' . qq( "select CONCAT('port: ', \@\@port) AS port" )); $msb->write_to('check_slaves', '>>', $replication_directory . '/master/use -e' . qq( 'show master status\\G' | grep "File\\|Position" )); $msb->write_to('check_slaves', '>>', 'for NNUM in ' . $slave_list ); $msb->write_to('check_slaves', '>>', 'do' ); $msb->write_to('check_slaves', '>>', ' echo "slave # $NNUM"'); $msb->write_to('check_slaves', '>>', ' ' . $replication_directory . '/node$NNUM/use -BN -e' . qq( "select CONCAT('port: ', \@\@port) AS port" )); $msb->write_to('check_slaves', '>>', ' ' . $replication_directory . '/node$NNUM/use -e' . qq( 'show slave status\\G' | grep "\\(Running:\\|Master_Log_Pos\\|\\write_to('check_slaves', '>>', 'done ' ); chmod 0755, 'check_slaves'; system "cp m n1"; chmod 0755, "n1"; for my $slave (1 .. $msb->{options}{how_many_slaves} ) { $msb->write_to("s$slave", '>', "#!/bin/sh"); $msb->write_to("s$slave", '>', qq($replication_directory/node$slave/use "\$@")); chmod 0755, "s$slave"; my $N=$slave+1; system "cp s$slave n$N"; chmod 0755, "s$slave"; chmod 0755, "n$N"; } $msb->write_to('initialize_slaves', '>', "#!/bin/sh"); $msb->write_to('initialize_slaves', '>>', ""); $msb->write_to('initialize_slaves', '>>', "# Don't use directly."); $msb->write_to('initialize_slaves', '>>', "# This script is called by 'start_all' when needed"); $msb->write_to('initialize_slaves', '>>', ""); for my $slave (1 .. $msb->{options}{how_many_slaves} ) { print "starting slave $slave\n"; system "./node$slave/start" and die "can't execute ./node$slave/start ($CHILD_ERROR $OS_ERROR)"; $msb->write_to('initialize_slaves', '>>', qq(echo "initializing slave $slave")); $msb->write_to('initialize_slaves', '>>', qq(echo 'CHANGE MASTER TO ) . qq( master_host="127.0.0.1", ) . qq( master_port=$replication_port, ) . qq( master_user="$MySQL::Sandbox::default_users{'repl_user'}", ) . qq( master_password="$MySQL::Sandbox::default_users{'repl_password'}" )); if ($master_use_gtid) { $msb->write_to('initialize_slaves', '>>', qq(, master_use_gtid=current_pos) ); } $msb->write_to('initialize_slaves', '>>', qq(' | $replication_directory/node$slave/use -u root ) ); $msb->write_to('initialize_slaves', '>>', qq( echo 'START SLAVE' ) . qq( | $replication_directory/node$slave/use -u root ) ); system "perl -i -pe 's/^password/#password/' ./node$slave/my.sandbox.cnf" } # # Creates the replication user # ##system qq(./m -u root -e 'grant replication slave on *.* ) ## . qq( to "$MySQL::Sandbox::default_users{'repl_user'}"\@"127.%" ) ## . qq( identified by "$MySQL::Sandbox::default_users{'repl_password'}"') ## and die "can't create slave user"; chmod 0755, "initialize_slaves"; system "./initialize_slaves" and die "can't initialize slave"; # # For the first run, there is root without password. # After the first run, a password is assigned # for my $slave (1 .. $msb->{options}{how_many_slaves} ) { system "perl -i -pe 's/^#password/password/' ./node$slave/my.sandbox.cnf" } # system q( perl -i -pe 's/(-u root) (--password=)/$1/g' initialize_slaves ); post_installation($replication_directory); $msb->write_to('README', '>', MySQL::Sandbox::Scripts::get_readme_master_slave()); $msb->write_to('README', '>>', MySQL::Sandbox::Scripts::get_readme_common_replication()); $msb->write_to('README', '>>', MySQL::Sandbox::Scripts::get_readme_common()); for my $json (qw(connection.json default_connection.json)) { my $json_text = MySQL::Sandbox::get_json_from_dirs(\@node_list, $json); $msb->write_to($json, '>', $json_text); } chdir $current_dir; print "replication directory installed in ", use_env($replication_directory), "\n"; # # instrumentation # sbinstr( "replication_directory installed in <" . use_env($replication_directory) . ">"); sub make_circular_replication { my $cmd = "make_multiple_sandbox --circular"; my $group_dir = 'rcsandbox_' . $dashed_version; if ($msb->{options}{replication_directory} ) { $group_dir = $msb->{options}{replication_directory}; } if ($msb->{options}{how_many_slaves}) { $cmd .= ' --how_many_nodes=' . $msb->{options}{how_many_slaves}; } $cmd .= ' --group_directory=' . $group_dir; if ($msb->{options}{sandbox_base_port} ) { $cmd .= ' --sandbox_base_port=' . $msb->{options}{sandbox_base_port} } else { $cmd .= ' --sandbox_base_port=' . ($defaults{circular_base_port} + ($release_no * 100)); } my $result = system "$cmd $msb->{options}{server_version}" ; post_installation("$msb->{options}{upper_directory}/$group_dir") unless $result; exit $result; } sub post_installation { my ($replication_directory) = @_; # print "++ post_installation: <$replication_directory> <$node_list_text> <$create_gtid_script>\n"; unless (-d $replication_directory) { die "Error in post_installation procedure. $replication_directory not found\n"; } chdir $replication_directory; my $gtid_script_template=<<'END_TEMPLATE'; #!/bin/bash cd _REPLICATION_DIR_ OPTIONS="master-info-repository=table " OPTIONS="$OPTIONS relay-log-info-repository=table" OPTIONS="$OPTIONS gtid_mode=ON" OPTIONS="$OPTIONS log-slave-updates enforce-gtid-consistency" CHANGED="" for NODE in _NODE_LIST_ do for OPTION in $OPTIONS do option_exists=$(grep $OPTION $NODE/my.sandbox.cnf) if [ -z "$option_exists" ] then echo "$OPTION" >> $NODE/my.sandbox.cnf echo "# option '$OPTION' added to $NODE configuration file" CHANGED=1 else echo "# option '$OPTION' already exists in $NODE configuration file" fi done done if [ -n "$CHANGED" ] then ./restart_all for NODE in _NODE_LIST_ do if [ "$NODE" != "master" ] then $NODE/use -e 'stop slave' $NODE/use -e 'CHANGE MASTER TO MASTER_AUTO_POSITION=1' $NODE/use -e 'start slave' fi done fi END_TEMPLATE $msb->write_to('test_replication', '>', '#!/bin/bash' ); my $test_replication="$ENV{SANDBOX_HOME}/test_replication"; $msb->write_to('test_replication', '>>', "cd $replication_directory" ); $msb->write_to('test_replication', '>>', "TEST_REPLICATION=$test_replication" ); $msb->write_to('test_replication', '>>', 'if [ -x $TEST_REPLICATION ]' ); $msb->write_to('test_replication', '>>', 'then' ); $msb->write_to('test_replication', '>>', ' $TEST_REPLICATION' ); $msb->write_to('test_replication', '>>', 'else' ); $msb->write_to('test_replication', '>>', ' echo "$TEST_REPLICATION not found"' ); $msb->write_to('test_replication', '>>', ' exit 1' ); $msb->write_to('test_replication', '>>', 'fi' ); chmod 0755, 'test_replication'; if ($create_gtid_script) { $gtid_script_template =~ s/_REPLICATION_DIR_/$replication_directory/; $gtid_script_template =~ s/_NODE_LIST_/$node_list_text/g; $msb->write_to('enable_gtid', '>', $gtid_script_template); chmod 0755, 'enable_gtid'; } } __END__ MySQL-Sandbox-3.1.04/bin/make_sandbox000755 000765 000024 00000024616 12566053633 017412 0ustar00gmaxstaff000000 000000 #!/usr/bin/perl # make_sandbox # The MySQL Sandbox # Copyright (C) 2006-2015 Giuseppe Maxia # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. use strict; use warnings; # use Data::Dumper; use English qw( -no_match_vars ); use MySQL::Sandbox qw( runs_as_root sbinstr); use Getopt::Long ; my $default_binary_base = $ENV{SANDBOX_BINARY} || ($ENV{HOME} . '/opt/mysql'); unless ( -d $default_binary_base ) { $default_binary_base = '/opt/mysql'; } my $binary_base = $ENV{'BINARY_BASE'} || $default_binary_base; my @prefixes = ('mysql', 'percona', 'mariadb'); my $default_prefix= 'mysql'; my %options = ( export_binaries => 0, add_prefix => '', ); my $msb = MySQL::Sandbox->new(); runs_as_root(); GetOptions( export_binaries => \$options{export_binaries}, 'add_prefix=s' => \$options{add_prefix}, # 'c|comment=s@' => \$options{comments} , 'help' => \$options{help}, ) or get_help('+++'); get_help() if $options{help}; my $where_to_install = shift or get_help("Binary tarball or expanded tarball directory needed\n"); my $version; my ($major, $minor, $release); $where_to_install =~ s{ / \s* $ }{}x; $where_to_install =~ s/^\s*\~/$ENV{HOME}/x; if ( $where_to_install =~ m{\.\./}) # it is a tricky path { die "relative paths must not contain '../' \n"; } # explicit current directory relative path if ( ((-f $where_to_install) # the file exists and ( $where_to_install =~ m{^\./}) # it identifies the current directory ) ) { $where_to_install =~ s[^\./][$ENV{PWD}/] ; unless ( ( -f $where_to_install) or (-d $where_to_install) ) { die "file not found in current directory ($where_to_install)\n"; } } # relative path if ( (( (-f $where_to_install) or ( -d $where_to_install)) # the file exists and ( $where_to_install !~ m{^/}) # it is not an absolute path ) ) { $where_to_install = $ENV{PWD} . '/' . $where_to_install; unless ( ( -f $where_to_install) or (-d $where_to_install) ) { die "file not found in current directory ($where_to_install)\n"; } } my $prefix_regex = join('|', @prefixes ); $prefix_regex = qr/(?:$prefix_regex)/i; #my $ignore_leading_number = 0; sub basename { my ($path) = @_; $path =~ s{.*/}{}; $path; } my $barename = basename($where_to_install); if ($barename =~ /^\d+\..*\.tar\.gz/) { # $ignore_leading_number = 1; if ($barename eq $where_to_install) { $where_to_install="$ENV{PWD}/$barename"; } } # current directory if ( $where_to_install =~ m{^(?:\d+\.)?$prefix_regex\D+\d+\.\d+\.\d+.*\.tar\.gz$ }x ) { $where_to_install = $ENV{PWD} . '/' . $where_to_install; unless ( -f $where_to_install ) { die "file not found in current directory ($where_to_install)\n"; } } # bare version directory under $HOME/opt/bin if ( $where_to_install =~ /^(?:[-_a-zAZ]+)?(\d+)\.(\d+)\.(\d+)/x ) { ($major, $minor, $release) = ($1, $2, $3); $version = $where_to_install; } # absolute version directory elsif ( $where_to_install =~ m{^(/.+)/(\d+)\.(\d+)\.(\d+)$}x ) { ($binary_base, $major, $minor, $release) = ($1, $2, $3, $4); $version = "$major.$minor.$release"; unless ( -d $where_to_install ) { die "directory not found ($where_to_install)\n"; } } # absolute version directory with prefix elsif (( -d "$ENV{SANDBOX_BINARY}/$where_to_install") && ($where_to_install =~ m{(\d+)\.(\d+)\.(\d+)$}x )) { ($binary_base, $major, $minor, $release) = ($ENV{SANDBOX_BINARY}, $1, $2, $3, $4); $version = "$major.$minor.$release"; } # absolute version directory elsif ( $where_to_install =~ m{^(/.+)/.*(\d+)\.(\d+)\.(\d+)$}x ) { ($binary_base, $major, $minor, $release) = ($1, $2, $3, $4); # print ">>$binary_base, $major, $minor, $release\n"; exit; $version = "$major.$minor.$release"; unless ( -d $where_to_install ) { die "directory not found ($where_to_install)\n"; } } # full path to tarball elsif ( $where_to_install =~ m{^(/.+)/(?:\d+\.)?($prefix_regex\D+(\d+)\.(\d+)\.(\d+)[^/]*)\.tar\.gz$ }x ) { my $new_dir; unless ( -f $where_to_install ) { die "tarball file not found ($where_to_install)\n"; } ($binary_base, $new_dir, $major, $minor, $release) = ($1, $2, $3, $4, $5); print "unpacking $where_to_install\n"; $version = "$major.$minor.$release"; my $tar_executable='no_such_program'; my $full_new_dir = "$binary_base/$options{add_prefix}$version"; if ( -d $full_new_dir ) { $where_to_install = $full_new_dir; } else { my $original_dir = $ENV{PWD}; my @recognized_tar_executables = qw(gtar gnutar bsdtar); my $which_tar; my $tar_found = 0; for my $tar_exec (@recognized_tar_executables) { $which_tar = qx(which $tar_exec); if ((!$which_tar) or ($which_tar =~ /^no/i)) { next } else { $tar_found = 1; last } } unless ($tar_found ) { $which_tar = qx(which tar ); if ((!$which_tar) or ($which_tar =~ /^no/i)) { $which_tar = undef; } } if ($which_tar) { chomp $which_tar; $tar_executable = $which_tar; my $tar_version = qx($tar_executable --version) or die "can't find tar program\n"; unless ($tar_version =~ /(?:bsdtar|gnu\s+tar)/i) { die "this version of tar is not supported\n"; } } else { die "tar program not found\n"; } chdir $binary_base or die "can't change directory to $binary_base\n"; my $tar_file = $where_to_install; $tar_file =~ s{^.*/}{}; my $result = system("gunzip -c $tar_file | $tar_executable -xf -"); if ($result) { die "error unpacking $tar_file ($!)\n"; } my $new_name = $options{add_prefix} . $version; if ($options{export_binaries} && ( -d $default_binary_base)) { $new_name = "$default_binary_base/$options{add_prefix}$version"; if ( -d $new_name) { warn "can't export to $binary_base. Directory $version already exists!\n"; $new_name = $options{add_prefix} . $version; } else { $full_new_dir = $new_name; $binary_base = $default_binary_base; } } my $rename_result = system "mv $new_dir $new_name"; if ($rename_result) { die "can't rename $new_dir to $new_name"; } # some versions of Perl and OS can't perform a rename across file systems # Bug #504789 #rename $new_dir, $new_name # or die "can't rename $new_dir to $new_name"; system "chmod -R ogu+r $new_name "; # Not sandbox related. # It is needed if the user wants # to run the test suite $where_to_install = $full_new_dir; chdir $original_dir; } } # not a full path elsif ($where_to_install =~ m{[^/].*\.tar\.gz$} ) { print "<$where_to_install>\n"; get_help( "You must enter a full path to the tarball. Relative paths are not supported.\n"); } # not a tarball elsif ($where_to_install =~ m{^/.*(?credits(), "\n"; if ($msg) { my $len = length($msg); $len = 80 if $len > 80; print '*' x $len, "\n", $msg, '*' x $len, "\n"; } print <\n";exit; unless ( -d $binary_base ) { die "$binary_base does not exist\n"; } my @supported_versions = @{ MySQL::Sandbox::supported_versions() }; my $simple_version = "$major.$minor"; unless ( grep { $simple_version eq $_ } @supported_versions) { die "unsupported version $simple_version\n"; } if ($release < 10) { $release = '0' . $release; } my $port = ($major . $minor. $release) ; if ($port < 1024) { $port .= '0'; } if ( -d "$binary_base/$bare_basedir" ) { my $text_version = $version; # $text_version =~ tr/./_/d; ## no critic $text_version =~ s/\./_/g; my @install_options = ( "--basedir=$binary_base/$bare_basedir", "--sandbox_directory=msb_$options{add_prefix}$text_version", "--install_version=$simple_version", "--sandbox_port=$port", "--no_ver_after_name", @ARGV ); if ($major >=4) { push(@install_options, qq(--my_clause=log-error=msandbox.err)); } unless (grep {$_ eq '--no_show'} @install_options) { print "Executing low_level_make_sandbox ", join( " \\\n\t", @install_options ), "\n"; } sbinstr( " low_level_make_sandbox called with params <" . join(";", @install_options) . ">"); exec "low_level_make_sandbox", @install_options; } else { die "there is no $bare_basedir directory under $binary_base\n"; } MySQL-Sandbox-3.1.04/bin/make_sandbox_from_installed000755 000765 000024 00000011354 12576721401 022463 0ustar00gmaxstaff000000 000000 #!/usr/bin/perl # make_sandbox_from_installed # The MySQL Sandbox # Copyright (C) 2006-2015 Giuseppe Maxia # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. use strict; use warnings; use MySQL::Sandbox qw(runs_as_root); runs_as_root(); my $new_version = shift or die "version needed\n"; if ($new_version =~ /^(-h|--help)$/) { print MySQL::Sandbox::credits(); print< 'my*', from => 'bin/', to => 'bin'}, {files => 'resolveip', from => 'bin/', to => 'bin'}, {files => 'mysql_install_db', from => 'scripts/', to => 'bin', optional => 1}, {files => 'mysql*', from => 'lib64/', to => 'lib', optional => 1}, {files => 'mysql*', from => 'lib/', to => 'lib', optional => 1}, {files => 'mysql*', from => 'libexec/', to => 'bin', optional =>1}, {files => 'mysql*', from => 'sbin/', to => 'bin', optional =>1}, {files => 'mysql/', from => 'share/', to => 'share', optional =>1}, ); my @commands; my @prefixes = ( '/usr', '/usr/local', '/usr/local/mysql', ); my $found_mysqld = 0; my $found_install_db = 0; my $found_libraries = 0; for my $prefix (@prefixes) { if ( (-x "$prefix/bin/mysqld") or (-x "$prefix/libexec/mysqld") or (-x "$prefix/sbin/mysqld") ) { $found_mysqld =1; } if ( (-x "$prefix/bin/mysql_install_db") or (-x "$prefix/scripts/mysql_install_db") ) { $found_install_db =1; } if ( glob("$prefix/lib/mysql/libmysqlclient*") or glob( "$prefix/lib/libmysqlclient*") or glob( "$prefix/lib64/libmysqlclient*") ) { $found_libraries =1; } } unless ($found_mysqld) { die "can't find mysqld in (@prefixes)\n"; } unless ($found_install_db) { die "can't find mysql_install_db in (@prefixes)\n"; } unless ($found_libraries) { die "can't find mysql libraries in (@prefixes)\n"; } for my $bin ( @binaries ) { my $found_prefix = undef; for my $prefix (@prefixes) { if ($bin->{files} =~ /\*/ ) { my @files = glob("$prefix/$bin->{from}/$bin->{files}"); if (@files) { $found_prefix = $prefix; last; } } else { if ( -e "$prefix/$bin->{from}/$bin->{files}") { $found_prefix = $prefix; last; } } } unless ( $found_prefix) { if ($bin->{optional}) { next; } die "can't find $bin->{from}/$bin->{files} under (@prefixes) \n"; } push @commands, sprintf("ln -s %s/%s/%s %s/%s/%s", $found_prefix, $bin->{from}, $bin->{files}, $current_dir, $new_version, $bin->{to} ); } unless (grep { /share/ } @commands) { if ( -d "/usr/local/mysql/share" ) { push @commands, "ln -s /usr/local/mysql/share/* $current_dir/$new_version/share"; } } #use Data::Dumper; #print Dumper \@commands; #exit; mkdir $new_version or die "can't create $new_version ($!)\n"; chdir $new_version; for my $dir (qw(bin lib share)) { mkdir $dir or die "can't create $new_version/$dir\n"; } for my $command (@commands) { system $command; if ($?) { die "error creating symbolic link ($command) \n"; } } $ENV{SANDBOX_BINARY} = $current_dir; system "make_sandbox $new_version -- @ARGV"; MySQL-Sandbox-3.1.04/bin/make_sandbox_from_source000755 000765 000024 00000016335 12611067376 022014 0ustar00gmaxstaff000000 000000 #!/usr/bin/perl # make_sandbox_from_source # The MySQL Sandbox # Copyright (C) 2006-2015 Giuseppe Maxia # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. use strict; use warnings; use MySQL::Sandbox qw(runs_as_root); runs_as_root(); my $msb = MySQL::Sandbox->new(); my $source_directory = shift or get_help('source directory missing'); my $sandbox_type = shift or get_help('sandbox_type missing'); my %sandbox_apps = ( single => 'make_sandbox', replication => 'make_replication_sandbox', circular => 'make_replication_sandbox', multiple => 'make_multiple_sandbox', ); unless ( -d $source_directory) { die "<$source_directory> is not a directory\n"; } $source_directory =~ s{/$}{}; unless ( -x "$source_directory/scripts/make_binary_distribution") { die "can't find executable script 'make_binary_distribution'\n"; } unless ( -x "$source_directory/sql/mysqld") { die "Can't find executable mysqld. Sources don't seem to have been compiled.\n"; } unless ($sandbox_apps{$sandbox_type}) { get_help("unsupported sandbox type ($sandbox_type)"); } chdir $source_directory or die "can't change path to <$source_directory>\n"; my $source_version = get_source_version(); my $old_tarball = last_tarball(); my $new_tarball; if ( $old_tarball ) { my @tgz = file_age($old_tarball); my @mysqld = file_age("./sql/mysqld"); my @dir = file_age($source_version) ; unless (@dir) { @dir = ('---', 0); } if (($mysqld[1] > $tgz[1]) or ($mysqld[1] > $dir[1])) { print " new build. The tarball needs to be redone\n"; $new_tarball = build_tarball(); # removing the directory if ( -d $source_version ) { remove_source_dir($source_version); } } elsif ($tgz[1] > $dir[1]) { print "tarball newer than the version directory\n"; # removing the directory if ( ( -d $source_version) && (( $tgz[1] - $dir[1] ) > 60 )) { remove_source_dir($source_version); } $new_tarball = $old_tarball; } elsif ( $dir[1] >= $tgz[1] ) { print "tarball older than directory\n"; # Nothing to be done $new_tarball = $source_version; } else { print "dir @dir\n"; print "mysqld @mysqld\n"; print "tgz @tgz\n"; die "unhandled \n"; } } else { print "no old tarball found\n"; $new_tarball = build_tarball(); } my $options = ''; if ( $sandbox_type eq 'circular') { $options = '--topology=circular'; } system "$sandbox_apps{$sandbox_type} $source_directory/$new_tarball $options @ARGV"; # # functions # sub build_tarball { my $result = system "./scripts/make_binary_distribution"; if ($result or $? ) { die "error creating binary tarball. ($result - $? - $! )"; } my $tarball = last_tarball() or die "can't find a tarball\n"; return $tarball; } sub get_source_version { # # Parses 'Makefile' for server version. # # 'Makefile' exists only after the server is compiled # but this is just as well in our case, since we only # need to run this script after the server is fully built. # This method should be more robust than parsing # configure.in # my $version; if ( -f 'VERSION' ) { open my $VFH, q{<}, 'VERSION' or die "can't open VERSION\n"; while (my $line = <$VFH>) { if ($line =~ /MYSQL_VERSION_(?:MAJOR|MINOR|PATCH)=(\d+)/) { if (defined $version) { $version .= '.'; } else { $version = ''; } $version .= $1; } } unless ($version =~ /\d+\.\d+\.\d+/) { die "could not find a version number in VERSION ($version)\n"; } return $version; } else { print "# There is no VERSION file in this directory.\n# Now trying with Makefile\n" if $MySQL::Sandbox::DEBUG; } open my $MAKEFILE, q{<}, 'Makefile' or die "can't find Makefile\n"; while (my $line = <$MAKEFILE>) { if ($line =~ / ^ # start of line \s* # optional whitespace MYSQL_NO_DASH_VERSION # literal \s* # optional whitespace = # equals sign \s* # optional whitespace (\d\.\d.\d+) # capture the version \s* # optional whitespace $ # end of line /x) { $version = $1; last; } } close $MAKEFILE; if ($version) { return $version; } else { die "can't find a version in Makefile\n"; } } #sub get_source_version { # open my $CONFIG, q{<}, 'configure.in' # or die "can't find configure.in\n"; # my $version; # while (my $line = <$CONFIG>) { # if ($line =~ / # (?:AM_INIT_AUTOMAKE # | # AC_INIT) # either of these macros # \D+ # followed by one or more non digit # (?:(?i)mysql) # followed by "mysql" in any case # \D+ # followed by one or more non digit # (\d\.\d.\d+) # capture the version # /x) { # $version = $1; # last; # } # } # close $CONFIG; # if ($version) { # return $version; # } # else { # die "can't find a version in configure.in\n"; # } #} sub last_tarball { my %files = map {file_age($_)} grep {$_ !~ /^mysql-\d\.\d\.\d+\.tar\.gz$/} glob("*.tar.gz"); return unless keys %files; return (sort { $files{$b} <=> $files{$a} } keys %files)[0]; } sub file_age { my ($filename) = @_; return unless -e $filename; my ($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$size, $atime,$mtime,$ctime,$blksize,$blocks) = stat($filename); return ($filename, $atime); } sub get_help{ my ($msg) = @_; print $msb->credits(), "\n"; if ($msg) { print "*** $msg\n"; } print <new(); my @apps = ( { name => 'make_sandbox', description => 'the easiest way of creating a sandbox', }, { name => 'low_level_make_sandbox', description => q{create a single sandbox, with fine tuning options (don't use directly)}, }, { name => 'make_replication_sandbox', description => 'creates a sandbox with replicated master and slaves or circular', }, { name => 'make_multiple_sandbox', description => 'creates a group of sandboxes with the same version', }, { name => 'make_multiple_custom_sandbox', description => 'create a group of sandboxes with different versions', }, { name => 'make_sandbox_from_source', description => 'create a sandbox from a build directory', }, { name => 'make_sandbox_from_installed', description => 'create a sandbox from already installed binaries', }, { name => 'sbtool', description => 'performs auxiliary actions with existing sandboxes', }, ); my $choice = shift or help(); if (grep {$choice eq $_->{name} } @apps ) { my $application = "$choice"; if ( -x $application) { exec $application, @ARGV; } else { die "application $application not found\n"; } } else { exec "perldoc MySQL::Sandbox"; #die "'$choice' is not an application in MySQL Sandbox\n"; } sub help { print $msb->credits(); print "available applications:\n"; for my $app (@apps) { printf " %-30s: %s\n", $app->{'name'}, $app->{'description'}; } exit(1); } __END__ MySQL-Sandbox-3.1.04/bin/msb000755 000765 000024 00000014421 12566053633 015531 0ustar00gmaxstaff000000 000000 #!/usr/bin/perl # msb # The MySQL Sandbox # Copyright (C) 2006-2015 Giuseppe Maxia # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. use strict; use warnings; use MySQL::Sandbox qw(runs_as_root); my $DEBUG = $MySQL::Sandbox::DEBUG; runs_as_root(); my $msb = MySQL::Sandbox->new(); my $version = shift or get_help(); my $group_prefix = ''; my $tarball = ''; if ( $version =~ /^[rm]$/) { $group_prefix = $version; $version = shift or get_help(); } $ENV{SANDBOX_HOME} = $ENV{SANDBOX_HOME} || "$ENV{HOME}/sandboxes"; #unless ( -d $ENV{SANDBOX_HOME} ) { # die "\$SANDBOX_HOME not found at $ENV{SANDBOX_HOME}\n"; #} $version =~ s/\s*//g; if ($version =~ /(\d)\.(\d)\.(\d+).*tar\.gz$/) { $tarball = $version; $version = "$group_prefix$1.$2.$3"; unless (-f $tarball) { die "file not found $tarball\n"; } } if ( $version =~ /^(\d)\.(\d)\.(\d+)$/ ) { # install single install_and_restart('single', $version, "$1$2$3"); } elsif ( $version =~ /^(r|m)(\d)\.(\d)\.(\d+)$/ ) { # install group my $group = $1; my $simple_version = "$2$3$4"; my %groupsb = ( r => 'replication', m => 'multiple', ); install_and_restart( $groupsb{$group}, $version, $simple_version); } if ($version =~ /^r(\d+)$/i) { # replication open_replication($1); } elsif ($version =~ /^m(\d+)$/i) { # multiple open_multi($1); } elsif ($version =~ /^\d+$/) { # open_single($version); } elsif (-d "$ENV{SANDBOX_HOME}/$version") { open_single($version, "nosearch"); } else { # this should fail when the directory is not found } sub find_sb { my ($prefix, $version) = @_; my @dirs = glob ("$ENV{SANDBOX_HOME}/$prefix*"); $prefix =~ s/_//g; for my $dir (@dirs) { my $simple_dir = $dir; $simple_dir =~ s{.*/}{}; $simple_dir =~ s/_//g; if ("$prefix$version" eq $simple_dir) { return $dir; } } return; } sub open_single { my ($version, $nosearch) = @_; my $sb_dir = find_sb('msb', $version); if ($nosearch) { $sb_dir= "$ENV{SANDBOX_HOME}/$version"; } else { $sb_dir = find_sb('msb', $version); } if ($sb_dir) { my ($pid) = glob("$sb_dir/data/*.pid"); unless ($pid) { system "$sb_dir/start"; } exec "$sb_dir/use", @ARGV; } else { die "can't find a matching sandbox for $version\n"; } } sub open_replication { my ($version) = @_; my $sb_dir = find_sb('rsandbox', $version); # print "replication ($sb_dir)\n"; if ($sb_dir) { my ($pid) = glob("$sb_dir/master/data/*.pid"); unless ($pid) { system "$sb_dir/start_all"; } my $item = 'm'; if ($ARGV[0] =~ /^\d+$/ ) { my $node = shift @ARGV; $item = "s$node"; } exec "$sb_dir/$item", @ARGV; } else { die "can't find a matching sandbox for $version\n"; } } sub open_multi { my ($version) = @_; my $sb_dir = find_sb('multi_msb', $version); if ($sb_dir) { my ($pid) = glob("$sb_dir/node1/data/*.pid"); unless ($pid) { system "$sb_dir/start_all"; } my $node = 1; if ($ARGV[0] =~ /^\d+$/ ) { $node = shift @ARGV; } exec "$sb_dir/n$node", @ARGV; } else { die "can't find a matching sandbox for $version\n"; } } sub get_help { my ($msg) = @_; if ($msg) { print "**** $msg\n"; } print $msb->credits(); print "MySQL Sandbox shortcut\n", "Invokes a single or group sandbox easily.\n", "(It will start the sandbox if it is not active).\n", "\n", "Usage: msb [r|m]version [node] [options]\n", #"\n", "\tr -> replication\tm -> multiple\n", "version could be a plain number to open a sandbox\n", "or a dotted number, to install it if it doesn't exist\n", "or the full path to a tarball\n", "\t[node] is used for r|m\n", "\t[options] are what you would pass to the sandbox app\n"; print "Examples:\n", "msb 5135\n", "# runs \$SANDBOX_HOME/msb_5_1_35/use\n", "\n", "msb 5.1.35\n", "# runs make_sandbox 5.1.35 and \$SANDBOX_HOME/msb_5_1_35/use\n", "\n", "msb r5135\n", "# runs \$SANDBOX_HOME/rsandbox_5_1_35/m\n", "\n", "msb r5.1.35\n", "# runs make_replication_sandbox 5.1.35 and \$SANDBOX_HOME/msb_5_1_35/use\n", "\n"; exit 1; } sub install_and_restart { my ($application, $version, $simple_version) = @_; my $cmd; my $prefix = ''; if ($version =~ /^([rm])/) { $prefix = $1; $version =~ s/^[rm]//; } my $uversion = $version; $uversion =~ s/\./_/g; my $run_installer = 1; if ($application eq 'single') { $cmd = 'make_sandbox ' . ($tarball || $version) . ' -- --no_confirm'; if ( -d "$ENV{SANDBOX_HOME}/msb_$uversion") { $run_installer = 0; } } elsif ($application eq 'replication') { $cmd = 'make_replication_sandbox ' . ($tarball || $version); if ( -d "$ENV{SANDBOX_HOME}/rsandbox_$uversion") { $run_installer = 0; } } elsif ($application eq 'multiple') { $cmd = 'make_multiple_sandbox ' . ($tarball || $version); if ( -d "$ENV{SANDBOX_HOME}/multi_msb_$uversion") { $run_installer = 0; } } else { die "unknown applicationn $application\n"; } if ($run_installer) { print "EXECUTING $cmd\n" if $DEBUG; my $result = system($cmd); if ($result) { die "installation error ($!)\n"; } } exec $0, "$prefix$simple_version", @ARGV; } MySQL-Sandbox-3.1.04/bin/sbtool000755 000765 000024 00000122774 12576721401 016261 0ustar00gmaxstaff000000 000000 #!/usr/bin/perl # sbtool # The MySQL Sandbox # Copyright (C) 2006-2015 Giuseppe Maxia # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. use strict; use warnings; use Carp; use English qw( -no_match_vars ); use Data::Dumper; use Getopt::Long qw(:config no_ignore_case ); use File::Copy qw/cp/; use File::Find; use MySQL::Sandbox qw( runs_as_root is_a_sandbox is_sandbox_running get_sandbox_params get_ports get_ranges get_option_file_contents sbinstr get_sb_info); use MySQL::Sandbox::Scripts; runs_as_root(); my $DEBUG = $MySQL::Sandbox::DEBUG; my $sandbox_options_file = $MySQL::Sandbox::sandbox_options_file; # my $sandbox_current_options = $MySQL::Sandbox::sandbox_current_options; my %supported_operations = %MySQL::Sandbox::Scripts::sbtool_supported_operations; # ports => 'lists ports used by the Sandbox', # range => 'finds N consecutive ports not yet used by the Sandbox', # info => 'returns configuration options from a Sandbox', # tree => 'creates a replication tree', # copy => 'copies data from one Sandbox to another', # move => 'moves a Sandbox to a different location', # port => 'Changes a Sandbox port', # delete => 'removes a sandbox completely', # preserve => 'makes a sandbox permanent', # unpreserve => 'makes a sandbox not permanent', # plugin => adds plugin support to a sandbox (innodb,semisynch) #); my %supported_formats = %MySQL::Sandbox::Scripts::sbtool_supported_formats; # text => 'plain text dump of requested information', # perl => 'fully structured information in Perl code', #); my $msb = MySQL::Sandbox->new(); $msb->parse_options(MySQL::Sandbox::Scripts::parse_options_sbtool()); # my %{$msb->{options}} = map { $_, $msb->{parse_options}{$_}{value} } keys %{$msb->{parse_options}}; GetOptions( map { $msb->{parse_options}{$_}{parse}, \$msb->{options}{$_} } keys %{$msb->{parse_options}} ) or get_help(); get_help() if $msb->{options}{help} or ! $msb->{options}{operation}; if ($msb->{options}{verbose}) { $DEBUG = $msb->{options}{verbose} unless $DEBUG; } sub croak_die { my ($msg) = @_; if ($DEBUG) { croak $msg; } else { die $msg; } } for my $op ( keys %{$msb->{parse_options}} ) { if ( $msb->{parse_options}{$op}{accepted} ) { my %accepted = %{ $msb->{parse_options}{$op}{accepted} }; for my $ak ( keys %accepted ) { unless ( exists $accepted{ $msb->{options}{$op} } ) { croak_die "invalid value '$msb->{options}{$op}' for option <$op>\n"; } } } } sbinstr( ' operation ' . $msb->{options}{operation} ); for my $dir (qw(source_dir dest_dir tree_dir search_path)) { if ($msb->{options}{$dir}) { $msb->{options}{$dir} =~ s/^\s*~/$ENV{HOME}/; } } if ( $msb->{options}{operation} eq 'ports' ) { get_ports(\%{$msb->{options}}); } elsif ( $msb->{options}{operation} eq 'info' ) { $msb->{options}{all_info} = 1; $msb->{options}{format} = 'perl'; get_ports(\%{$msb->{options}}); } elsif ( $msb->{options}{operation} eq 'range' ) { get_ranges(\%{$msb->{options}}) } elsif ( $msb->{options}{operation} eq 'tree' ) { make_tree($msb->{options}{tree_dir} ) } elsif ( $msb->{options}{operation} eq 'move' ) { move_sandbox( $msb->{options}{source_dir}, $msb->{options}{dest_dir} ); } elsif ( $msb->{options}{operation} eq 'port' ) { unless ($msb->{options}{new_port}) { croak_die "operation 'port' requires new_port option\n"; } move_sandbox( $msb->{options}{source_dir}, $msb->{options}{source_dir}, 'alreday_moved' ); } elsif ( $msb->{options}{operation} eq 'copy' ) { copy_single_sandbox( $msb->{options}{source_dir}, $msb->{options}{dest_dir} ); } elsif ( $msb->{options}{operation} eq 'preserve' ) { preserve_sandbox($msb->{options}{source_dir}) } elsif ( $msb->{options}{operation} eq 'unpreserve' ) { unpreserve_sandbox($msb->{options}{source_dir}) } elsif ( $msb->{options}{operation} eq 'delete' ) { for my $opt (qw(dest_dir new_port only_used all_info )) { if ( $msb->{options}{$opt} ) { croak_die "option <$opt> is incompatible with the requested operation (delete)\n"; } } delete_sandbox( $msb->{options}{source_dir}); } elsif ($msb->{options}{operation} eq 'plugin') { add_plugin( $msb->{options}{source_dir}, $msb->{options}{plugin}, $msb->{options}{plugin_file} ); } else { croak_die "unsupported operation ($msb->{options}{operation})\n"; } sub get_help { my ($msg) = @_; print MySQL::Sandbox::credits(); if ($msg) { print '*' x 50; print "\n", $msg, "\n"; print '*' x 50; print "\n"; } print "usage: $PROGRAM_NAME [options] \n"; for my $op ( sort { $msb->{parse_options}{$a}{so} <=> $msb->{parse_options}{$b}{so} } keys %{$msb->{parse_options}} ) { my $val = $msb->{options}{$op}; my $parse = $msb->{parse_options}{$op}{parse}; my $expected = '-'; if ( $parse =~ s/=(.+)// ) { $expected = $1; } my ( $short, $long ) = split /\|/, $parse; unless ($long) { $long = $short ; $short = ''; } printf "\t%s%-5s --%-15s (%s) <%s> - %s\n", ($short? '-' : ' '), $short, $long, $expected, $val || '', $msb->{parse_options}{$op}{help} || ''; if ( $msb->{parse_options}{$op}{accepted} ) { my %accepted = %{ $msb->{parse_options}{$op}{accepted} }; for my $ao ( keys %accepted ) { printf "\t\t %-10s %s\n", "'$ao'", $accepted{$ao}; } } } exit 1; } sub make_tree { my ($dir) = @_; unless ( $dir) { croak_die "you must set the directory using the 'tree_dir' option\n"; } unless ( -d $dir ) { croak_die "directory ($dir) does not exist\n"; } my $master = $msb->{options}{master_node} || 1; if ($msb->{options}{tree_nodes} ) { my ($m, $mid, $leaf) = split /-/, $msb->{options}{tree_nodes}; if ($m) { $master = $m; } else { croak_die " master not defined in tree_nodes\n"; } if ($mid) { $msb->{options}{mid_nodes} = $mid; } else { croak_die " middle nodes not defined in tree_nodes\n"; } if ($leaf) { $msb->{options}{leaf_nodes} = $leaf; } else { croak_die " leaf nodes not defined in tree_nodes\n"; } } my @MID_NODES = split ' ', $msb->{options}{mid_nodes} or croak_die "no mid nodes selected. Use the --mid_nodes option\n"; for my $mid (@MID_NODES) { croak_die "middle nodes must be numeric" unless $mid =~ /^\d+$/; } my @LEAF_NODES = (); my @chunks = split /\|/, $msb->{options}{leaf_nodes} or croak_die "no leaf nodes selected. Use the --leaf_nodes option\n"; # print Data::Dumper->Dump([\@chunks], ['chunks']); for my $c (@chunks) { my @leaf = split ' ', $c; croak_die "empty leaf node\n" unless @leaf; for my $ln (@leaf) { croak_die "leaf nodes must be numeric" unless $ln =~ /^\d+$/; } push @LEAF_NODES, [@leaf]; } # print Data::Dumper->Dump([\@MID_NODES], ['MID_NODES']); # print Data::Dumper->Dump([\@LEAF_NODES], ['LEAF_NODES']); if ( @LEAF_NODES != @MID_NODES) { croak_die "you must specify at least one leaf node for each middle node\n"; } for my $node (( $master, @MID_NODES, map {@$_} @LEAF_NODES)) { if ( ! -d "$dir/node$node" ) { croak_die "node $node does not exist\n"; } } my ($N1INFO, $N1PORT)=get_node_info($dir, $master); unless ($N1PORT) { croak_die "can't get the port for node$master\n" . "make sure the node is running\n"; } my $CHANGE_MASTER_Q= "CHANGE MASTER TO master_host='127.0.0.1', " . "master_user='msandbox', master_password='msandbox'," . "master_port="; print "$dir/use_all 'reset master'\n"; system "$dir/use_all 'reset master'"; print "$dir/stop_all\n"; system "$dir/stop_all"; print "node $master is master\n"; unless ( -e $N1INFO->{opt}{socket}) { system "$dir/node$master/start" } system qq(echo "$dir/use_all 'stop slave'" > $dir/clear_all); system qq(echo "$dir/use_all 'stop slave'" > $dir/stop_all); system qq(echo "" > $dir/send_kill_all); system qq(echo "$dir/node$master/start" > $dir/start_all); for my $mid_node ( @MID_NODES ) { my ($MID_NODE_INFO, $MID_NODE_PORT)=get_node_info($dir, $mid_node); unless ( -e $MID_NODE_INFO->{opt}{socket}) { system "$dir/node$mid_node/start"; } my $HAS_UPDATES=`grep log_slave_updates $dir/node$mid_node/my.sandbox.cnf`; my $HAS_REPORT=`grep "report-host" $dir/node$mid_node/my.sandbox.cnf`; unless ($HAS_REPORT) { system qq( echo "report-host=node$mid_node" >> $dir/node$mid_node/my.sandbox.cnf) ; system qq( echo "report-port=$MID_NODE_PORT" >> $dir/node$mid_node/my.sandbox.cnf) ; } unless ( $HAS_UPDATES) { print "enabling node $mid_node to relay updates\n"; system qq(echo "log_slave_updates" >> $dir/node$mid_node/my.sandbox.cnf) ; system qq($dir/node$mid_node/restart) ; } system qq($dir/n$mid_node -e "stop slave") ; system qq($dir/n$mid_node -e "$CHANGE_MASTER_Q $N1PORT") ; system qq($dir/n$mid_node -e "start slave") ; print " node $mid_node is slave of node $master\n"; my $l_nodes = shift @LEAF_NODES; system qq(echo "$dir/node$mid_node/start" >> $dir/start_all); for my $leaf_node (@$l_nodes) { my ($LEAF_NODE_INFO, $LN_PORT) = get_node_info($dir, $leaf_node); unless ( -e $LEAF_NODE_INFO->{opt}{socket}) { system "$dir/node$leaf_node/start"; } check_report($dir,$leaf_node, 1, $MID_NODE_PORT, $LN_PORT); system qq($dir/n$leaf_node -e "stop slave"); system qq($dir/n$leaf_node -e "$CHANGE_MASTER_Q $MID_NODE_PORT"); system qq($dir/n$leaf_node -e "start slave"); print " node $leaf_node is slave of node $mid_node\n"; system qq(echo "$dir/node$leaf_node/stop" >> $dir/stop_all); system qq(echo "$dir/node$leaf_node/clear" >> $dir/clear_all); system qq(echo "$dir/node$leaf_node/send_kill" >> $dir/send_kill_all); system qq(echo "$dir/node$leaf_node/start" >> $dir/start_all); } system qq(echo "$dir/node$mid_node/stop" >> $dir/stop_all); system qq(echo "$dir/node$mid_node/clear" >> $dir/clear_all); system qq(echo "$dir/node$mid_node/send_kill" >> $dir/send_kill_all); } system qq(echo "$dir/node$master/stop" >> $dir/stop_all); system qq(echo "$dir/node$master/clear" >> $dir/clear_all); system qq(echo "$dir/node$master/send_kill" >> $dir/send_kill_all); } sub check_report { my ($dir, $node, $restart, $master_port, $this_node_port) = @_; my $HAS_REPORT=`grep "report-host" $dir/node$node/my.sandbox.cnf`; unless ($HAS_REPORT) { system qq(echo "report-host=node$node" >> $dir/node$node/my.sandbox.cnf); system qq(echo "report-port=$this_node_port" >> $dir/node$node/my.sandbox.cnf); if ($restart) { system qq($dir/node$node/restart); } } } sub get_node_info { my ($dir, $node) = @_; my ( $info ) = get_sandbox_params("$dir/node$node"); # print Dumper($ports, $all_info); confess "can't read port for node $node" unless $info; return ($info, $info->{opt}{port}); } sub move_sandbox { my ($source, $dest) = @_; unless ($source) { croak_die "Need a source directory (--source_dir)\n"; } unless ($dest) { croak_die "Need a destination directory (--dest_dir)\n"; } $dest =~ s/^\s//; $dest =~ s/\s*$//; $source =~ s/^\s//; $source =~ s/\s*$//; $source =~ s/^\s*~/$ENV{HOME}/; $dest =~ s/^\s*~/$ENV{HOME}/; unless (($source =~ m{^/}) && ($dest =~ m{^/}) ) { croak_die "Source and destination directories must be absolute paths.\n"; } unless ( -d $source ) { croak_die "directory $source does not exist\n"; } if ( -x "$source/start") { if (( $source eq $dest) and $msb->{options}{new_port}) { move_single_sandbox($source, $dest, "already_moved"); } else { move_single_sandbox($source, $dest); } } elsif ( -x "$source/start_all") { move_multiple_sandbox($source, $dest); } else { croak_die "directory $source does not seem to be a sandbox\n"; } } sub move_multiple_sandbox { my ($old_dir, $new_dir) = @_; unless ( -d $old_dir ) { croak_die " directory $old_dir doesn't exist\n"; } if ( -d $new_dir ) { croak_die "directory $new_dir already exists\n"; } if ( -x "$old_dir/stop_all" ) { system "$old_dir/stop_all"; my $timeout = 5; while ( file_exists($old_dir, '\.pid$')) { $timeout--; sleep 1; } } else { croak_die "$old_dir does not seem to contain a multiple sandbox\n"; } my @old_subdirs = grep { -d $_ } glob("$old_dir/*/"); for my $od (@old_subdirs) { unless ( -x "$od/change_paths" ) { croak_die "directory $od is not a sandbox created with version 2.0.15+\n"; } } my $result = system "mv $old_dir $new_dir"; if ($result) { croak_die "unable to move sandbox $old_dir to $new_dir ($OS_ERROR)\n"; } my @new_subdirs = (); for my $od (@old_subdirs) { my $nd = $od; if (($nd =~ s/$old_dir/$new_dir/ ) && ( -d $nd )) { push @new_subdirs, [$od, $nd]; } else { # reverting to old directory system "mv $new_dir $old_dir"; croak_die "can't move directory $od to $nd\n"; } } for my $sd (@new_subdirs) { move_single_sandbox( $sd->[0], $sd->[1], "already_moved" ); } chdir $new_dir; unless ($old_dir =~ m{/$} ) { $old_dir .= '/'; } unless ($new_dir =~ m{/$} ) { $new_dir .= '/'; } my @nodes = glob("n[0-9]*"); my @slaves = glob("s[0-9]*"); my @scripts = qw(m start_all stop_all clear_all send_kill_all check_slaves use_all initialize_slaves); for my $script (( @nodes, @slaves, @scripts ) ) { if ( -x $script ) { system q(perl -i.bak -pe 'BEGIN{$old=shift;$new=shift};s/$old/$new/g') . " $old_dir $new_dir $script " ; } } } sub file_exists { my ($dir,$pattern) = @_; my $file_count =0; find ( sub { $file_count++ if $File::Find::name =~ /$pattern/; }, $dir ); return $file_count; } sub move_single_sandbox { my ($old_dir, $new_dir, $already_moved) = @_; unless ( $already_moved) { unless ( -d $old_dir ) { croak_die " directory $old_dir doesn't exist\n"; } } if ( -d $new_dir && (! $already_moved ) ) { croak_die "directory $new_dir already exists\n"; } unless ( (-e "$old_dir/change_paths") or ( $already_moved && -e "$new_dir/change_paths") ) { croak_die "script 'change_paths' not found. " . "Please get it from any Sandbox installed with version 2.0.15+\n"; } if ($already_moved) { if (is_sandbox_running($new_dir)) { stop_sandbox($new_dir); } } else { stop_sandbox($old_dir); my $result = system qq(mv $old_dir $new_dir) ; if ($result) { croak_die "unable to move sandbox $old_dir to $new_dir ($OS_ERROR)\n"; } } chdir $new_dir; unless ( $old_dir eq $new_dir) { system "./change_paths $old_dir $new_dir"; } if ($msb->{options}{new_port}) { unless ($msb->{options}{new_port} =~ /^\d+$/) { croak_die "new port must be numerical ($msb->{options}{new_port})\n"; } if (($msb->{options}{new_port} <= 1024) or ( $msb->{options}{new_port} > 32000)) { croak_die "new port out of range ($msb->{options}{new_port}) - " . "it must be between 1025 and 32000\n"; } unless ( -e "$new_dir/change_ports" ) { croak_die "script 'change_ports' not found. " . "Please get it from any Sandbox installed with version 2.0.18+\n"; } system "./change_ports $msb->{options}{new_port}"; } } sub stop_sandbox { my ($sbdir) = @_; my ($info) = get_sandbox_params($sbdir); if ( -x "$sbdir/stop" ) { system "$sbdir/stop"; my $timeout = 5; while ($timeout && ( -e $info->{opt}{socket} )) { $timeout--; sleep 1; } if ( -e $info->{opt}{socket} ) { croak_die "sandbox in $sbdir is still running. Unable to stop it\n"; } } else { croak_die "$sbdir does not seem to contain a sandbox\n"; } } sub clone_sandbox_data { my ($source_dir, $dest_dir) = @_; croak_die "source directory missing\n" unless $source_dir; croak_die "destination directory missing\n" unless $dest_dir; $source_dir =~ s{/\s*$}{}; unless (-d $source_dir) { croak_die "<$source_dir> is not a valid directory\n"; } unless (-d $dest_dir) { croak_die "<$dest_dir> is not a valid directory\n"; } # checking if it is a valid data directory unless (-d "$source_dir/mysql") { croak_die "<$source_dir> is not a valid data directory\n" } my @pids = glob( "$source_dir/*.pid" ); if (@pids) { croak_die "it seems that your sandbox is running. Please stop it and try again\n"; } my @skip_files = map {qr/$_/} ( '^relay-log\.info$', '\.err$', '-bin\.\d+$', '-bin\.index$', '-relay-bin\.\d+$', '-relay-bin\.index+$', ); find ( { no_chdir => 1, follow => 1, wanted => sub { my $dir = $File::Find::dir; my $fname = $File::Find::name; $dir =~ s{/$}{}; $dir =~ s{.*/}{}; $fname =~ s{.*/}{}; # print "<$File::Find::name><$File::Find::dir> [$dir] [$fname]\n"; return if $dir =~ /^\./; return if $File::Find::name eq $source_dir; for my $skip (@skip_files) { return if $fname =~ $skip ; } if ( -d $File::Find::name ) { if ( -d "$dest_dir/$fname" ) { return; } elsif ( -f "$dest_dir/$fname" ) { croak_die "<$dest_dir/$fname> already exists and it is not a directory\n"; } print_debug( "creating $dest_dir/$fname\n"); my $result = mkdir "$dest_dir/$fname"; unless ($result) { croak_die "error creating directory ($!)\n"; } } elsif ( -f $File::Find::name ) { # print "$Find::File::dir eq $source_dir\n"; if ((! $File::Find::dir) or ($File::Find::dir eq $source_dir)) { $dir = ''; } print_debug( "$File::Find::name -> $dest_dir/$dir/$fname\n"); my $result = cp $File::Find::name, "$dest_dir/$dir/$fname"; unless ($result) { croak_die "error copying file $!\n"; } } else { croak_die "unhandled file $File::Find::name\n"; } } }, $source_dir ); } sub print_debug { my ($msg, $level) = @_; $level |= 1; if ($DEBUG >= $level) { print $msg; } } sub copy_single_sandbox { my ($source_dir, $dest_dir) = @_; if ($msb->{options}{new_port}) { croak_die "option 'new_port' is not supported with 'copy'\n"; } unless ( $source_dir) { croak_die " source directory missing\n"; } unless ( -d $source_dir) { croak_die " <$source_dir> not found\n"; } unless ( $dest_dir) { croak_die " destination directory missing\n"; } unless ( -d $dest_dir) { croak_die " destination directory <$dest_dir> not found\n"; } my ($srunning, $ssboptions) = is_sandbox_running($source_dir); my ($drunning, $dsboptions) = is_sandbox_running($dest_dir); my ($source_version, $dest_version); unless ($srunning) { system "$source_dir/start"; unless ( -e $ssboptions->{opt}{'pid_file'} ) { croak_die "unable to start source sandbox\n"; } } $source_version = `$source_dir/use -B -N -e "select version()"`; system "$source_dir/stop"; if ( -e $ssboptions->{opt}{'pid_file'} ) { system "$source_dir/send_kill"; } unless ($drunning) { system "$dest_dir/start"; unless ( -e $ssboptions->{opt}{'pid_file'} ) { croak_die "unable to start destination sandbox\n"; } } $dest_version = `$dest_dir/use -B -N -e "select version()"`; system "$dest_dir/stop"; if ( -e $dsboptions->{opt}{'pid_file'} ) { system "$dest_dir/send_kill"; } if (substr($source_version, 0,3) ne substr($dest_version,0,3)) { croak_die "can't copy from $source_dir to $dest_dir. Not the same major version\n"; } clone_sandbox_data( "$source_dir/data", "$dest_dir/data"); } sub delete_sandbox { my ($source) = @_; unless ($source) { croak_die "Need a source directory (--source_dir)\n"; } $source =~ s/^\s//; $source =~ s/\s*$//; $source =~ s{/$}{}; $ENV{SANDBOX_HOME} =~ s{/$}{}; $source =~ s/^\s*~/$ENV{HOME}/; unless ($source =~ m{^/} ) { croak_die "Source directory must be an absolute path.\n"; } if ($source eq $ENV{SANDBOX_HOME} ) { croak_die "Source directory must not be the whole sandbox home ($ENV{SANDBOX_HOME}.)\n"; } unless ( -d $source ) { croak_die "directory $source does not exist\n"; } my $cmd1 = undef; my $cmd2 = undef; if (( -e "$source/no_clear" ) or ( -e "$source/no_clear_all")) { print " script found.\nDirectory <$source> can't be deleted. It's a permanent sandbox.\n"; exit 0; } if ( (-x "$source/clear") && (-x "$source/stop" )) { $cmd1 = "$source/stop"; $cmd2 = "$source/clear"; } elsif ( (-x "$source/clear_all") && (-x "$source/stop_all")) { $cmd1 = "$source/stop_all"; $cmd2 = "$source/clear_all"; } else { croak_die "directory $source does not seem to be a sandbox\n"; } $OS_ERROR = undef; $CHILD_ERROR = 0; print "$cmd1\n" if $msb->{options}{verbose}; system($cmd1); if ($CHILD_ERROR or $OS_ERROR) { croak_die "error stopping sandbox at $source\n ($CHILD_ERROR - $OS_ERROR)"; } print "$cmd2\n" if $msb->{options}{verbose}; system($cmd2); if ($CHILD_ERROR or $OS_ERROR) { croak_die "error clearing sandbox at $source\n ($CHILD_ERROR - $OS_ERROR)"; } system("rm -rf $source"); if ($CHILD_ERROR or $OS_ERROR) { croak_die "error deleting sandbox at $source\n ($CHILD_ERROR - $OS_ERROR)"; } print "sandbox at <$source> has been removed\n"; } sub preserve_sandbox { my ($source) = @_; unless ($source) { croak_die "Need a source directory (--source_dir)\n"; } $source =~ s/^\s//; $source =~ s/\s*$//; $source =~ s/^\s*~/$ENV{HOME}/; unless ($source =~ m{^/} ) { croak_die "Source directory must be an absolute path.\n"; } unless ( -d $source ) { croak_die "directory $source does not exist\n"; } if (( -e "$source/no_clear") or (-e "$source/no_clear_all" ) ) { croak_die " script found.\nDirectory <$source> is already a permanent sandbox.\n"; } my $old_clear = undef; if ( -x "$source/clear") { $old_clear = 'clear'; } elsif ( -x "$source/clear_all") { $old_clear = 'clear_all'; } else { croak_die "directory $source does not seem to be a sandbox\n"; } if ($old_clear eq "clear_all") { my @dirs = grep { (-d $_) && ( -e "$_/clear" ) } glob("$source/*"); for my $dir (@dirs) { preserve_sandbox($dir); } } chdir $source; rename $old_clear, "no_$old_clear"; open my $CLEAR, q{>}, $old_clear or croak_die "can't create $old_clear"; print $CLEAR qq(echo "This sandbox is permanent."\n); print $CLEAR qq(echo "The '$old_clear' command has been disabled."\n); print $CLEAR qq(echo "The contents of the old '$old_clear' command are in the 'no_$old_clear' file"\n); close $CLEAR; chmod 0755, $old_clear; chmod 0644, "no_$old_clear"; print "sandbox at <$source> is now permanent\n"; } sub unpreserve_sandbox { my ($source) = @_; unless ($source) { croak_die "Need a source directory (--source_dir)\n"; } $source =~ s/^\s//; $source =~ s/\s*$//; $source =~ s/^\s*~/$ENV{HOME}/; unless ($source =~ m{^/} ) { croak_die "Source directory must be an absolute path.\n"; } unless ( -d $source ) { croak_die "directory $source does not exist\n"; } if (( ! -e "$source/no_clear") and (! -e "$source/no_clear_all" ) ) { croak_die " script not found.\nDirectory <$source> is not a permanent sandbox.\n"; } my $old_clear = undef; if ( -f "$source/no_clear") { $old_clear = 'no_clear'; } elsif ( -f "$source/no_clear_all") { $old_clear = 'no_clear_all'; } else { croak_die "directory $source does not seem to be a sandbox\n"; } my $new_clear = $old_clear; $new_clear =~ s/^no_//; unless (-f "$source/$new_clear") { croak_die "Can't find the '$new_clear' script. This may not be a preserved sandbox.\n"; } if ($old_clear eq "no_clear_all") { my @dirs = grep { (-d $_) && ( -e "$_/no_clear" ) } glob("$source/*"); for my $dir (@dirs) { unpreserve_sandbox($dir); } } chdir $source; system "rm -f $new_clear"; rename $old_clear, $new_clear; chmod 0755, $new_clear; print "sandbox at <$source> is now NOT PERMANENT\n"; } # # ---- Plugin # sub add_plugin { my ($source_dir, $plugin, $plugin_file) = @_; unless ($source_dir) { croak_die "Need a source directory (--source_dir)\n"; } unless ($plugin) { croak_die "Need a plugin (--plugin)\n"; } $plugin =~ s/^\s//; $plugin =~ s/\s*$//; $source_dir =~ s/^\s//; $source_dir =~ s/\s*$//; $source_dir =~ s/\/$//; $source_dir =~ s/^\s*~/$ENV{HOME}/; unless ( -d $source_dir ) { croak_die "directory $source_dir does not exist\n"; } if ( exist_all($source_dir, [qw(start stop restart use clear)]) ) { add_plugin_single($source_dir, $plugin, $plugin_file); } elsif ( exist_all($source_dir, [ qw(start_all stop_all restart_all use_all clear_all)]) ) { add_plugin_multiple($source_dir, $plugin, $plugin_file); } else { croak_die "directory $source_dir does not seem to be a sandbox\n"; } } # # Finds the plugin configuration file (or uses an explicit one) # # Gets the contents of the plugin configuration file # sub get_plugin_conf { my ($directory, $plugin, $plugin_conf_file) = @_; if ($plugin_conf_file) { unless ( -f $plugin_conf_file) { croak_die "could not find $plugin_conf_file \n"; } } else { $plugin_conf_file = "$directory/plugin.conf"; unless ( -f $plugin_conf_file) { $plugin_conf_file = "$ENV{'SANDBOX_HOME'}/plugin.conf"; } unless ( -f $plugin_conf_file) { croak_die "could not find plugin.conf " . "in $directory or in $ENV{'SANDBOX_HOME'}\n"; } } our $plugin_definition; open my $FH, '<', $plugin_conf_file or croak_die "can't open $plugin_conf_file ($!)\n"; my $contents =''; while (my $line = <$FH>) { $contents .= $line; } close $FH; eval $contents; if ($@) { croak_die "error processing plugin configuration file $plugin_conf_file\n" . "$@\n"; } unless (exists $plugin_definition->{$plugin}) { croak_die "the required plugin ($plugin) was not found in the " . "configuration file ($plugin_conf_file)\n"; } unless ( ref($plugin_definition->{$plugin}) && (ref( $plugin_definition->{$plugin}) eq 'HASH')) { croak_die "the definition of plugin '$plugin' must be a hash ref\n"; } return ($plugin_conf_file, $plugin_definition->{$plugin}); } # # Returns true if a given option is set in a hash. # The option could be written with dashes ('-') # or underscores ('_') # sub is_option_set { my ($href, $value) = @_; my $value1 = $value; my $value2 = $value; $value1 =~ s/[_-]/-/g; $value2 =~ s/[_-]/_/g; # print "<$value1> <$value2>\n";exit; return (defined($href->{$value1}) or defined($href->{$value2})) ; } sub add_plugin_single { my ($directory, $plugin, $plugin_conf_file) = @_; my $is_slave = 0; my $is_master = 0; my $options_from_file = get_option_file_contents("$directory/my.sandbox.cnf"); # print Dumper $options_from_file; # # it is a slave if slave related options # are found in the options file # if (($options_from_file->{prompt} =~ /slave/) && is_option_set( $options_from_file, 'report-host') ) { $is_slave =1; } # # covers circular replication where a slave can also be a master # if ($is_slave && is_option_set($options_from_file, 'auto_increment_increment') && is_option_set($options_from_file, 'auto_increment_offset') && is_option_set($options_from_file, 'replicate-same-server-id') && is_option_set($options_from_file, 'log-slave-updates') ) { $is_master = 1; } # # The normal case: a master is such when its directory # is called *master/ and there is a prompt named "master" # something in its options file # elsif ( ( $directory =~ m{master/?} ) && ( $options_from_file->{prompt} =~ /master/ ) ) { $is_master =1; } my $plugin_conf; # # reads the plugin configuration file # ($plugin_conf_file, $plugin_conf) = get_plugin_conf( $directory, $plugin, $plugin_conf_file); # # Looks for plugin libraries inside the options # my %plugin_libs = (); for my $mode (qw(all_servers master slave)) { next unless defined $plugin_conf->{$mode}; for my $item ( qw(operation_sequence options_file sql_commands startup_file )) { unless ($plugin_conf->{ $item }) { $plugin_conf->{$item} = []; } unless (ref($plugin_conf->{$item}) eq 'ARRAY') { croak_die "$item must be an array ref\n"; } } for my $line ( @{$plugin_conf->{$mode}{options_file}}, @{$plugin_conf->{$mode}{sql_commands}}) { while ( $line =~ /([-\w]+\.so)/g ) { $plugin_libs{ $1 }++; } } } # # looks for the plugin directory # my $basedir = get_basedir($directory); my $plugindir = "$basedir/lib/plugin"; unless ( -d $plugindir ) { $plugindir = "$basedir/lib/mysql/plugin"; croak_die "could not find $plugindir\n" unless -d $plugindir; } # # makes sure that the plugin libraries # mentioned in the configuration file exist # for my $lib (keys %plugin_libs) { unless ( -f "$plugindir/$lib" ) { croak_die "could not find plugin '$lib' in $plugindir\n"; } } # All elements found. Now we can do the deed. # # Defines which installation modes to use # my @install_defs = (); if ($plugin_conf->{'all_servers'}) { push @install_defs, 'all_servers'; } if ($is_master) { push @install_defs, 'master'; } if ($is_slave) { push @install_defs, 'slave'; } unless (@install_defs) { croak_die "No installation instructions found\n" . "You must define one or more of " . "'all_servers', 'master', or 'slave'\n"; } # # Runs the installation parts # for my $inst_def (@install_defs) { next unless defined $plugin_conf->{$inst_def}; my $opseq = $plugin_conf->{$inst_def}{operation_sequence}; # print Dumper $plugin_conf;exit; # # Makes sure that the plugin configuration # contains a sequence of desired operations # unless ( defined $opseq ) { croak_die "plugin definition in $plugin_conf_file " . "($plugin, $inst_def) must " . "contain 'operation_sequence'\n"; } # # Loops through the requested operations # for my $op (@$opseq) { # # If it is a script found in the sandbox, run it # if ( grep { $op eq $_} qw(start stop clear restart) ) { my $result = system "$directory/$op"; croak_die "error executing $op\n" if $result; } # # Runs an update of the options file # elsif ( $op eq 'options_file' ) { #print "<<$plugindir>>\n"; update_options_file( "$directory/my.sandbox.cnf", 'mysqld', $plugin_conf->{$inst_def}{'options_file'}, $plugindir ); } # # Creates a startup file # elsif ( $op eq 'startup_file' ) { fill_startup_file( "$directory/data/startup.sql", $plugin_conf->{$inst_def}{'startup_file'} ); } # # Runs a batch of SQL commands # elsif ( $op eq 'sql_commands' ) { run_sql_commands ($directory, $plugin_conf->{$inst_def}{'sql_commands'} ); } # # Nothing else is recognized. # else { croak_die "unrecognized command $op in operation_sequence\n"; } } } } sub run_sql_commands { my ($directory, $queries) = @_; unless ( -x "$directory/use" ) { croak_die "can't execute sql queries in $directory " . "('./use' script not found)\n"; } my $tmp_file = "$directory/tmpqueries0"; while (-f $tmp_file) { $tmp_file =~ s/(\d+)$/$1 + 1/e; } # # Creates a temporary files, filled with queries # open my $FH, '>', $tmp_file or croak_die "can't open $tmp_file"; my $semicolon_found = 0; for my $query (@$queries) { print $FH $query; if ($query =~ /\s*;$/) { $semicolon_found =1; } } close $FH; if ($semicolon_found) { # # Runs the queries # my $result = system "$directory/use -vv -e 'source $tmp_file' "; unlink $tmp_file; if ($result) { croak_die "error running queries\n"; } } else { unlink $tmp_file; croak_die "Could not find any semicolon in the SQL list.\n" . "Please add at least one semicolon at the end of the" . " last line\n"; } } sub update_options_file { my ( $fname, $section, $contents, $plugindir ) = @_; # print "<<* $plugindir>>\n"; my @old_contents ; unless (-f $fname) { croak_die "can't find file $fname\n"; } open my $FH, '<', $fname or croak_die "can't open $fname\n"; @old_contents = <$FH>; close $FH; my $found_section = 0; my $found_plugindir = 0; # # Checks for the wanted section to be updated # And for already existing commands in the options file # for my $old_line (@old_contents) { chomp $old_line; if ($old_line =~ /\[$section\]/) { $found_section =1; } for my $new_line (@$contents) { chomp $new_line; if ($old_line =~ /^\s*(plugin[_-]dir)\s*=\s*(.*)/) { my $key = $1; my $old_plugindir = $2; $old_plugindir =~ s/\s*$//; $old_plugindir =~ s/\/$//; $plugindir =~ s/\s*$//; $plugindir =~ s/\/$//; if ($old_plugindir ne $plugindir) { $old_line = "$key = $plugindir"; } $found_plugindir = 1; next; } if ($old_line eq $new_line) { croak_die "option file already contains the line <$old_line>\n"; } } } unless ($found_section) { croak_die "could not find section [$section] in $fname\n"; } rename $fname, "$fname.bak" or croak_die "could not rename $fname to $fname.bak ($!)\n"; open $FH, '>', $fname or croak_die "can't create $fname\n"; # # If there was no plugin_dir in the old file # the we add it to the new options # unless ($found_plugindir && $plugindir) { unshift @$contents, "plugin_dir = $plugindir"; } my $in_wanted_section = 0; # # Writes the updated options file # for my $old_line (@old_contents) { if ($old_line =~ /^\s*\[$section\]/) { $in_wanted_section =1; } # # If a new section starts, # the new options are inserted # elsif ($old_line =~ /^\s*\[/) { if ($in_wanted_section) { $in_wanted_section = 0; insert_new_options ($FH, $contents); } } print $FH $old_line, "\n"; } # # If we reached the end of the file without # new sections, it means that we are still in the # wanted section and we add the new options here. if ($in_wanted_section) { $in_wanted_section =0; insert_new_options($FH, $contents); } close $FH; } sub insert_new_options { my ($FH, $contents) = @_; print $FH "#\n# Lines added on ", scalar(localtime), "\n#\n"; for my $nl (@$contents) { print $FH $nl, "\n"; } print $FH "#\n# --- END \n#\n"; } sub fill_startup_file { my ( $fname, $contents ) = @_; my @old_contents ; if (-f $fname) { open my $FH, '<', $fname or croak_die "can't open $fname\n"; @old_contents = <$FH>; close $FH; for my $old_line (@old_contents) { chomp $old_line; for my $new_line (@$contents) { chomp $new_line; if ($old_line eq $new_line) { croak_die "startup file already contains the line <$old_line>\n"; } } } rename $fname, "$fname.bak" or croak_die "could not rename $fname to $fname.bak ($!)\n"; } open my $FH, '>>', $fname or croak_die "can't create $fname\n"; insert_new_options($FH, $contents); close $FH; } sub add_plugin_multiple { my ($directory, $plugin, $plugin_file) = @_; my @dirs = grep { -d $_ } glob( "$directory/*/" ) ; my $result = system "$directory/stop_all"; croak_die "error running stop_all in $directory\n" if $result; for my $dir (@dirs) { if ( exist_all($dir, [qw(start stop restart use clear)]) ) { print "Installing <$plugin> in <$dir>\n"; add_plugin_single($dir, $plugin, $plugin_file); } else { print STDERR "WARNING: directory $dir is not a sandbox\n"; } } } sub get_basedir { my ($dir) = @_; unless ( -f "$dir/start" ) { croak_die "can't find file 'start' in $dir\n"; } open my $FH, '<', "$dir/start" or croak_die "can't open $dir/start ($!)\n"; my $basedir = undef; while ( (!$basedir) && (my $line =<$FH>)) { chomp $line; if ($line =~ /^BASEDIR=(\S+)/) { $basedir = $1; $basedir =~ s/^['" ]//; $basedir =~ s{['"/ ]+$}{}; } } close $FH; croak_die "could not find BASEDIR in $dir/start\n" unless $basedir; return $basedir; } sub exist_all { my ($directory, $files) = @_; for my $file ( @$files ) { unless ( -x "$directory/$file" ) { return 0; } } return 1; } MySQL-Sandbox-3.1.04/bin/test_sandbox000755 000765 000024 00000142171 12631425773 017452 0ustar00gmaxstaff000000 000000 #!/usr/bin/perl # test_sandbox # The MySQL Sandbox # Copyright (C) 2006-2015 Giuseppe Maxia # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. use strict; use warnings; use Data::Dumper; use Getopt::Long qw(:config no_ignore_case ); use MySQL::Sandbox qw(use_env greater_version); use English qw( -no_match_vars ); use Carp; my $DEBUG = $MySQL::Sandbox::DEBUG; for my $prog (qw( make_sandbox make_replication_sandbox make_multiple_sandbox make_multiple_custom_sandbox sbtool ) ) { unless ( exists_in_path ($prog) ) { die "script <$prog> not found\n"; } } sub tprint; sub tprintf; sub get_exec_result ; my $use_open3 = 0; eval "use IPC::Open3"; if ($@) { $use_open3 =0; } # # defaults # # my @versions = ( '5.0.51', '5.0.64', '5.1.23', '5.1.24', '5.1.25', '5.1.26', '6.0.6' ); my @versions = ( '5.0.86', '5.1.43'); my $verbose = $DEBUG || $ENV{'VERBOSE'} || 0; my %tests = ( tarball => 1, single => 1, replication => 1, circular => 1, multiple => 1, custom => 1, tuning => 1, sbtool => 0, smoke => 0, user => 0, ); my %expected_scripts = ( single => { executables => [qw(start stop clear msb send_kill status change_ports change_paths my restart use json_in_db)], texts => [qw( grants.mysql my.sandbox.cnf connection.json default_connection.json README)], }, replication => { executables => [qw(start_all stop_all clear_all send_kill_all status_all check_slaves restart_all use_all initialize_slaves m s1 s2 )], texts => [qw(connection.json default_connection.json README)], }, multiple_custom => { executables => [qw(start_all stop_all clear_all send_kill_all status_all restart_all use_all n1 )], texts => [qw(connection.json default_connection.json README)], }, multiple => { executables => [qw(start_all stop_all clear_all send_kill_all status_all restart_all use_all n1 n2 n3 )], texts => [qw(connection.json default_connection.json README)], }, circular => { executables => [qw(start_all stop_all clear_all send_kill_all status_all check_slaves restart_all use_all set_circular_replication.sh n1 n2 n3 )], texts => [qw(connection.json default_connection.json README)], }, ); # my %custom_tests = (); my ($user_tests, $user_versions, $user_defined_test, $get_help, $preserve_tests, ); GetOptions( "tarball|versions=s" => \$user_versions, "tests=s" => \$user_tests, "user_test=s"=> \$user_defined_test, "verbose" => \$verbose, "preserve_tests" => \$preserve_tests, "help|h" => \$get_help, ) or help(); help() if $get_help; if ($user_versions) { my @new_versions = grep {$_} split /,/, $user_versions; die "at least one version is required\n" unless @new_versions; @versions =(); # ensuring that each version is used only once. @new_versions = map { $_->[0] } # sorting with the Schwartzian Transform sort { $a->[1] cmp $b->[1] } map { /(\d+)\.(\d+)\.(\d+)/; [ $_, sprintf('%02d-%02d-%02d',$1,$2,$3)] } keys %{{ map { $_, 1} @new_versions }}; for my $ver (@new_versions) { push @versions, $ver; } } for my $ver (@versions) { $ver =~ s/^~/$ENV{'HOME'}/; unless (( -d "/opt/mysql/$ver") or ( -d "$ENV{'HOME'}/opt/mysql/$ver") or ( -f $ver )) { print "version $ver not found in either /opt/mysql or $ENV{'HOME'}/opt/mysql\n"; die "use --versions to list the versions you want to test\n"; } } if ($user_defined_test and !$user_tests) { $user_tests = 'user'; } if ($user_tests) { my @todo = grep {$_} split /,/, $user_tests; die "at least one test is required\n" unless @todo; my %new_tests; for my $t (@todo) { if (exists $tests{$t} ) { $new_tests{$t}++; } else { die "unrecognized test <$t>\n"; } } for my $t (keys %tests) { if ( exists $new_tests{$t} ) { $tests{$t} = 1; } else { $tests{$t} = 0; } } } my $sandbox_home = "$ENV{'HOME'}/sandboxes"; my %test_results = ( run => 0, passed => 0, failed => 0, skipped => 0, ); # # cleaning up existing sandbox directory # if ( $ENV{'SANDBOX_HOME'} ) { $sandbox_home = $ENV{'SANDBOX_HOME'}; } else { $ENV{'SANDBOX_HOME'} = $sandbox_home; } my $sh_stop_all = "$sandbox_home/stop_all"; if ( -x $sh_stop_all ) { system("$sh_stop_all > /dev/null 2>&1"); } # # setting the current sandbox directory for this test # $sandbox_home = $ENV{'TEST_SANDBOX_HOME'} || "$ENV{'HOME'}/test_sb"; $ENV{'SANDBOX_HOME'} = $sandbox_home; $sh_stop_all = "$sandbox_home/stop_all"; my $sh_clear_all = "$sandbox_home/clear_all"; my $sh_start_all = "$sandbox_home/start_all"; my $sh_use_all = "$sandbox_home/use_all"; if ($tests{'smoke'} and $tests{'sbtool'}) { die "test and test should not run together\n"; } # # cleaning up the test directory if exists # if ( -x $sh_stop_all ) { system("$sh_stop_all > /dev/null 2>&1"); system qq(rm -rf $sandbox_home) ; } # # checking if there are other servers running # my $how_many_mysqld = get_number_of_processes('mysqld'); my $how_many_mysqld_safe = get_number_of_processes('mysqld_safe'); tprintf "** currently there are (%d) mysqld processes and (%d) mysqld_safe processes\n", $how_many_mysqld, $how_many_mysqld_safe; # # starting the tests # for my $ver (@versions) { my ($bare_version, $version) = get_bare_version ($ver); if ($tests{'tarball'}) { # print "run_tarball_test($ver, $version, $bare_version)\n"; run_tarball_test($ver, $version, $bare_version); } if ($tests{'single'}) { # print "run_single_test($ver, $version, $bare_version)\n"; run_single_test($ver, $version, $bare_version); } if ($tests{'replication'} ) { run_replication_test($ver, $version, $bare_version); } if ($tests{'circular'}) { run_circular_test($ver, $version, $bare_version); } if ($tests{'multiple'}) { run_multiple_test($ver, $version, $bare_version); } } if ($tests{'custom'}) { run_mcustom_test(); } if ($tests{'user'}) { die "test file required\n" unless $user_defined_test; run_user_defined_test($user_defined_test); } my $summaries = 0; for my $test (keys %tests) { if ($tests{$test} && ($test !~ /^(?:tuning|smoke|sbtool|user)$/)) { $summaries = 1; last; } } if ($summaries) { run_summary_tests(); } if ($tests{'tuning'}) { run_tuning_test(); } if ($tests{'smoke'}) { for my $ver ( @versions ) { if (-f "$sandbox_home/stop_all") { system qq("$sandbox_home/stop_all > /dev/null 2>&1"); system qq(rm -rf $sandbox_home/*) ; } run_smoke_test($ver); } } if ($tests{'sbtool'}) { for my $ver (@versions) { if ( -d $sandbox_home ) { system "$sandbox_home/stop_all > /dev/null 2>&1"; system "rm -rf $sandbox_home"; } run_sbtool_test ($ver); } } tprintf "*** Executed %d tests. Passed %d (%5.2f%%). Failed %d (%5.2f%%)\n", $test_results{'run'}, $test_results{'passed'}, $test_results{'run'} ? $test_results{'passed'} / $test_results{'run'} * 100 : 0, $test_results{'failed'}, $test_results{'run'} ? $test_results{'failed'} / $test_results{'run'} * 100 : 0 ; if ($test_results{'failed'}) { exit 1; } # # ROUTINES # # # get_exec_result # # runs a shell command and returns the output # sub get_exec_result { if ($use_open3) { return get_exec_result_open3(@_); } else { return get_exec_result_qx(@_); } } sub get_exec_result_qx { my ($cmd) = @_; print "qx(shell) $cmd\n" if $verbose; my $output = qx($cmd 2>/tmp/err$$); if ($?) { die ("error executing $cmd ($!)\n"); } if ( -f "/tmp/err$$") { open my $efh, '<', "/tmp/err$$" or die "can't open /tmp/err$$ ($!)\n"; my $err_output=''; while (my $line = <$efh>) { next if $line =~ /Warning: Using a password/; $err_output .= $line; } close $efh; unlink "/tmp/err$$"; #if ($err_output) #{ # warn "# error executing $cmd\n"; # warn "#$err_output"; #} } print "qx(shell) $output\n" if $verbose; return $output; } sub get_exec_result_open3 { my ($cmd) = @_; print "o3(shell) $cmd\n" if $verbose; my ($out, $in, $err) = (undef, undef, 1); my $result = open3($in, $out, $err, $cmd ); my $output =''; my $err_output =''; while (my $line = <$out>) { $output .= $line; } while (my $line = <$err>) { $err_output .= $line; } if ($? or $err_output) { die ("error executing $cmd ($! - $err_output)\n"); } print "o3(shell) $output - $err_output\n" if $verbose; return $output; } # # get_sql_result # # runs a SQL command and returns the output # sub get_sql_result { my ($sb, $query) = @_; print "(sql) $query\n" if $verbose; if ( -f "$sb/use" ) { # print qq(\n); my $command = 'use -N -B '; if ($query =~ /show\s+slave\s+status.*\\G/i) { $command = 'use -B'; } my $output = qx(echo "$query" | $sb/$command ); if (defined $output) { chomp $output; } else { $output = ''; } if ($verbose && $verbose > 1) { print "$output\n"; } die "error executing query $query on sandbox $sb\n" if $?; return $output; } else { die "can't find a 'use' command on $sb\n"; } } # # get_number_of_processes # # returns the number of processes for a given name # sub get_number_of_processes { my ($proc_name) = @_; my $grep_cmd = 'ps -ef | grep -w %s | grep -v "grep -w %s" | wc -l '; my $cmd = sprintf($grep_cmd, $proc_name, $proc_name ); tprint "$cmd\n" if ($verbose && ($verbose > 1)); my $how_many = get_exec_result($cmd, 0); return $how_many; } # # help # # displays option for this program # sub help { my $HELP = <<"HELP"; test for MySQL Sandbox usage: $0 [options] --versions=version1[,version2,version3] uses specific versions for testing. currently: (@{[join ",", @versions]}) --tarball=/path/to/tarball it's an alias for --versions --tests=testname[,testname,testname] executes specific tests. currently: (@{[join ",", grep {$tests{$_}} keys %tests]}) --user_test=filename executes user defined tests from given file (implies --tests=user) --preserve_tests does not remove sandboxes at the end of the suite. --verbose shows the commands executed during tests --help shows this help HELP print $HELP; exit(1); } # # TEST ROUTINES # # # ok # # evaluates a condition and prints a ok/not ok message # sub ok ($;$) { my ($condition, $msg) = @_; # print Dumper \@_; $msg = '***' unless defined $msg; $test_results{'run'}++; if ($condition) { $test_results{'passed'}++; } else { print "not "; $test_results{'failed'}++; } print "ok $test_results{'run'} - $msg\n"; if ($verbose) { die "halting the test on verbose\n" unless $condition; } return $condition; } sub check_sandbox_files { my ($sandbox_type, $sandbox_path) = @_; for my $executable_script (@{ $expected_scripts{$sandbox_type}{executables} }) { ok( -x "$sandbox_path/$executable_script", "executable script $executable_script file found"); } for my $text_script (@{$expected_scripts{$sandbox_type}{texts} }) { my $filename = "$sandbox_path/$text_script"; ok( -f $filename, "text script $text_script file found"); if ($filename =~ /\.json$/) { my $is_json = MySQL::Sandbox::validate_json_object($filename); if ($is_json && ($is_json == -1)) { ok( 1, " - skipped $filename validation"); } else { ok($is_json, "JSON validation $filename"); } } } } sub run_tarball_test{ my ($ver, $version, $bare_version) = @_; # print "ver $ver - version $version - bare_version $bare_version\n"; exit; # ver ma10.0.13 - version ma10_0_13 - bare_version 10.0.13 # ver 5.7.8 - version 5_7_8 - bare_version 5.7.8 # ver ps5.6.40 - version ps5_6_40 - bare_version 5.6.40 my $prefix=''; my $prefix_option=''; my $tmpdir = $ENV{TMPDIR} || '/tmp'; if (! -d $tmpdir) { die "Can't find temporary directory $tmpdir\n"; } $tmpdir =~ s{/$}{}; my $tardir="$tmpdir/tmp$$"; mkdir $tardir; if ( ! -d $tardir) { die "Error creating $tardir\n"; } my @name_patterns = ( 'Percona-Server-_VER_-rel61.0.tar.gz', 'mariadb-_VER_-osx10.9-x86_64.tar.gz', 'mysql-_VER_-osx10.6-x86_64.tar.gz', 'mysql-_VER_-m11-osx10.6-x86_64.tar.gz', 'mysql-advanced-_VER_-osx10.7-x86_64.tar.gz', 'mysql-_VER_-labs-multi-src-rep.tar.gz', '13242627.mysql-_VER_-rc-osx10.8-x86_64.tar.gz', ); unless ($ENV{SANDBOX_BINARY}) { die "Variable SANDBOX_BINARY not set\n"; } unless (-d $ENV{SANDBOX_BINARY}) { die "Directory $ENV{SANDBOX_BINARY} not found\n"; } my $curdir = $ENV{PWD}; if ($ver =~ /^(\D+)/) { $prefix = $1; } for my $pattern (@name_patterns) { $pattern =~ s/_VER_/$ver/; chdir $tardir; my $pattern_dir= $pattern; $pattern_dir =~ s/\.tar.gz//; $pattern_dir =~ s{^\d+\.}{}; system "cp -R $ENV{SANDBOX_BINARY}/$ver $pattern_dir" ; ok(-d "$tardir/$pattern_dir", "$tardir/$pattern_dir exists") or exit 1; system "tar -c $pattern_dir | gzip -c > $pattern"; system "rm -rf $pattern_dir"; chdir $curdir; ok(! -d "$tardir/$pattern_dir", "$tardir/$pattern_dir was removed") or exit 1; ok( -f "$tardir/$pattern", "$tardir/$pattern exists") or exit 1; if ($prefix) { $prefix_option= "--add_prefix=$prefix"; } ok_exec( { command => "make_sandbox $prefix_option $tardir/$pattern -- --no_confirm", expected => 'sandbox server started', msg => "single tarball SB ($bare_version) started" }); ok(-d "$tardir/$ver", "$tardir/$ver was created") or exit 1; ok(-d "$sandbox_home/msb_$version", "$sandbox_home/$version was created") or exit 1; # check_sandbox_files( 'single', "$sandbox_home/msb_$version"); ok_sql( { path => "$sandbox_home/msb_$version", query => 'select version(), @@server_id', expected => $bare_version, msg => "single tarball SB version ($bare_version) SQL" }); ok_exec( { command => "sbtool -o delete -s $sandbox_home/msb_$version", expected => 'has been removed', msg => "single tarball SB ($bare_version) removed" }) or exit 1; system "rm -rf $tardir/$ver"; ok(! -d "$tardir/$bare_version", "$tardir/$bare_version was removed") or exit 1; system "rm -f $tardir/$pattern"; ok(! -f "$tardir/$pattern", "$tardir/$pattern was removed") or exit 1; } system "rm -rf $tardir"; } sub run_single_test { my ($ver, $version, $bare_version) = @_; ok_exec( { command => "make_sandbox $ver -- --no_confirm", expected => 'sandbox server started', msg => "single SB ($bare_version) started" }); check_sandbox_files( 'single', "$sandbox_home/msb_$version"); ok( -f "$sandbox_home/plugin.conf", "plugin template file found"); ok_exec( { command => "perl -c $sandbox_home/plugin.conf > /dev/null 2>&1", expected => 'ok', msg => "plugin template compiles OK" }); ok_sql( { path => "$sandbox_home/msb_$version", query => 'select version(), @@server_id', expected => $bare_version, msg => "single SB ($bare_version) SQL" }); get_sql_result( "$sandbox_home/msb_$version", 'create database \`a-a\`', # Bug#278394 - this will fail on 'clear' if not fixed $verbose ); } sub ok_sql { my ($params, $wanted_result) = @_; for my $p (qw(path query expected msg)) { unless (defined $params->{$p}) { croak "parameter <$p> not defined\n"; } } my $result = get_sql_result( $params->{'path'}, $params->{'query'}, $verbose); if ($wanted_result && ref($wanted_result) eq 'SCALAR') { $$wanted_result = $result; } if (! ref($params->{'expected'}) ) { if ($params->{'expected'} =~ /^ok$/i) { return ok($CHILD_ERROR == 0 , $params->{'msg'}); } elsif ($params->{'expected'} =~ s/^\!//) { return ok( $result !~ /$params->{'expected'}/i , $params->{'msg'}); } else { return ok( $result =~ /$params->{'expected'}/i , $params->{'msg'}); } } elsif (ref($params->{'expected'}) eq 'ARRAY') { my $count = 0; for my $expected (@{$params->{'expected'}}) { $count++; if ($expected =~ /^ok$/i) { ok($CHILD_ERROR == 0 , $params->{'msg'} . "-[$count]"); } elsif ( $expected =~ s/^!//) { ok( $result !~ /$expected/i , $params->{'msg'} . "-[$count]"); } else { ok( $result =~ /$expected/i , $params->{'msg'} . "-[$count]"); } } } else { croak "parameter 'expected' is neither a scalar nor an array reference\n"; } } sub ok_exec { my ($params) = @_; for my $p (qw(command expected msg)) { unless (defined $params->{$p}) { croak "parameter <$p> not defined\n"; } } my $return_code_wanted = 0; if (ref $params->{'expected'}) { $return_code_wanted = grep { /^ok$/i} @{ $params->{'expected'}}; } else { $return_code_wanted = $params->{'expected'} =~ /^ok$/i; } my $result; if ($return_code_wanted) { $result = get_exec_result_qx($params->{'command'}); } else { $result = get_exec_result($params->{'command'}); } if ($verbose) { print $result, "\n"; } if (! ref $params->{'expected'} ) { if ($return_code_wanted) { return ok($CHILD_ERROR == 0 , $params->{'msg'}); } elsif ($params->{'expected'} =~ s/^\!//) { return ok( $result !~ /\Q$params->{'expected'}\E/, $params->{'msg'} ); } else { return ok( $result =~ /\Q$params->{'expected'}\E/, $params->{'msg'} ); } } elsif (ref( $params->{'expected'}) eq 'ARRAY') { my $count =0; for my $expected (@{$params->{'expected'}}) { $count++; if ($expected =~ /^ok$/i) { ok( $CHILD_ERROR == 0 , $params->{'msg'} . "-[$count]"); } elsif ($expected =~ s/^\!//) { ok( $result !~ /\Q$expected\E/, $params->{'msg'} . "-[$count]" ); } else { ok( $result =~ /\Q$expected\E/, $params->{'msg'} . "-[$count]" ); } } } else { croak "parameter 'expected' is neither a scalar nor an array reference\n"; } } sub run_replication_test { my ($ver, $version, $bare_version) = @_; ok_exec({ command => "make_replication_sandbox $ver", expected => '!not started yet', msg => "replication sandbox ($bare_version) started" }); check_sandbox_files( 'replication', "$sandbox_home/rsandbox_$version"); ok_sql ({ path => "$sandbox_home/rsandbox_$version/master", query => 'select version(), @@server_id', expected => [ $bare_version, '\b1\s*$'], msg => "replication SB master ($bare_version) SQL - version - server_id" }); sleep 1; for my $node (1, 2) { ok_sql ({ path => "$sandbox_home/rsandbox_$version/node$node", query => 'select version(), @@server_id', expected => [ $bare_version, '\b10' . $node . '\s*$'], msg => "replication SB slave$node ($bare_version) SQL - version - server_id" }); } ok_sql ({ path => "$sandbox_home/rsandbox_$version/master", query => q{drop table if exists test.t1; create table test.t1 (id int); show tables from test}, expected => 't1', msg => "replication SB - table created on master" }); for my $node (1, 2) { ok_sql ({ path => "$sandbox_home/rsandbox_$version/node$node", query => q{show tables from test}, expected => 't1', msg => "replication SB - table exists on slave$node" }); } } sub run_circular_test { my ($ver, $version, $bare_version) = @_; ok_exec({ command => "make_replication_sandbox --how_many_slaves=3 --topology=circular $ver", expected => '!not started yet', msg => "circular replication sandbox ($bare_version) started", }); check_sandbox_files( 'circular', "$sandbox_home/rcsandbox_$version"); for my $node ( 1 .. 3) { ok_sql ({ path => "$sandbox_home/rcsandbox_$version/node$node", query => 'show slave status\G', expected => [ 'IO_Running.+Yes', 'SQL_Running.+Yes' ], msg => "circular replication SB node$node ($bare_version) SQL - Running" } ); sleep 1; } } sub run_multiple_test { my ($ver, $version, $bare_version) = @_; ok_exec({ command => "make_multiple_sandbox $ver", expected => 'group directory installed', msg => "multiple sandbox ($bare_version) started" }); check_sandbox_files( 'multiple', "$sandbox_home/multi_msb_$version"); for my $node (1 .. 3 ) { ok_sql({ path => "$sandbox_home/multi_msb_$version/node$node", query => 'select version(), @@server_id', expected => [ $bare_version, '\b10' . $node . '\s*$' ], msg => "multiple SB node $node ($bare_version) SQL - version - server_id" }); } } sub run_mcustom_test { my $gdname = 'multi_cmsb_' . get_bare_version($versions[0]) ; #$custom_dir =~ s/ /-/g; #$custom_dir =~ s/\./_/g; # $DEBUG=2; $verbose=2; $gdname =~ s/\./_/g; my $custom_dir = "$sandbox_home/$gdname"; ok_exec({ command => "make_multiple_custom_sandbox --group_directory=$gdname @versions ", expected => [ '!not started yet', "group directory installed in " . use_env($custom_dir) ], msg => "custom sandbox ( ". use_env($custom_dir)." ) started" }); ok(-d $custom_dir, 'custom group directory exists') or die "custom group directory not created\n"; check_sandbox_files('multiple_custom', $custom_dir); my $counter = 0; for my $ver (@versions) { my $bare_version = get_bare_version($ver); $counter++; if ( -d "$custom_dir/node$counter" ) { ok_sql({ path => "$custom_dir/node$counter", query => 'select version(), @@server_id', expected => [$bare_version, '\b10' . $counter . '\s*$'], msg => "multiple custom SB node $counter ($bare_version) SQL - version - server_id" }); } else { ok(1, 'test skipped'); } } } sub run_summary_tests { my $new_mysqld_procs = get_number_of_processes('mysqld'); my $new_mysqld_safe_procs = get_number_of_processes('mysqld_safe'); tprintf "** created (%d) mysqld processes and (%d) mysqld_safe processes\n", $new_mysqld_procs - $how_many_mysqld, $new_mysqld_safe_procs - $how_many_mysqld_safe; my $instances = ( 1 * $tests{'single'} # single + 3 * $tests{'replication'} # replicated + 3 * $tests{'circular'} # circular + 3 * $tests{'multiple'} # multiple ); my $expected_processes = $instances * scalar(@versions) + (scalar(@versions) * $tests{'custom'}) ; # custom counts only once ok( $expected_processes == ($new_mysqld_safe_procs - $how_many_mysqld_safe), "expected processes ($expected_processes)" ); tprint "** stopping all - please wait\n"; my $stop_all = get_exec_result("$sandbox_home/stop_all"); $new_mysqld_procs = get_number_of_processes('mysqld'); $new_mysqld_safe_procs = get_number_of_processes('mysqld_safe'); tprintf "** (%d) mysqld processes and (%d) mysqld_safe processes\n", $new_mysqld_procs - $how_many_mysqld, $new_mysqld_safe_procs - $how_many_mysqld_safe; ok( ($new_mysqld_safe_procs - $how_many_mysqld_safe ) == 0, 'expected processes (0)' ); tprint "** starting all - please wait\n"; my $start_all = get_exec_result("$sandbox_home/start_all"); $new_mysqld_procs = get_number_of_processes('mysqld'); $new_mysqld_safe_procs = get_number_of_processes('mysqld_safe'); tprintf "** created (%d) mysqld processes and (%d) mysqld_safe processes\n", $new_mysqld_procs - $how_many_mysqld, $new_mysqld_safe_procs - $how_many_mysqld_safe; ok( $expected_processes == ($new_mysqld_safe_procs - $how_many_mysqld_safe), "expected processes ($expected_processes)" ); unless ($ENV{'PRESERVE_TESTS'} or $preserve_tests) { tprint "** cleaning up - please wait\n"; my $clear_all = get_exec_result("$sandbox_home/clear_all"); $new_mysqld_procs = get_number_of_processes('mysqld'); $new_mysqld_safe_procs = get_number_of_processes('mysqld_safe'); tprintf "** (%d) mysqld processes and (%d) mysqld_safe processes\n", $new_mysqld_procs - $how_many_mysqld, $new_mysqld_safe_procs - $how_many_mysqld_safe; ok( ($new_mysqld_safe_procs - $how_many_mysqld_safe ) == 0, 'expected processes (0)' ) or die "can't continue without a clean environment\n"; system qq(rm -rf $sandbox_home/*) ; } } sub run_tuning_test { my $ver; for my $v (@versions) { $ver = $v; if ($ver =~ /^[^34]/) { last; } } if ($ver =~ /^[34]/) { print "skipping tuning test. It requires version >=5\n"; return; } my ($bare_version, $version) = get_bare_version($ver); if (($bare_version =~ /^5\.([567])/ ) || ($bare_version =~ /^10/ )) { for my $i ( 1 .. 6) { print "ok - skipped (this test is not available in MySQL $bare_version)\n"; } return; } ok_exec({ command => "make_sandbox $ver -- --no_confirm -c skip-innodb -c sql_mode=strict_all_tables", expected => 'sandbox server started', msg => 'tuning server created', }); ok_sql({ path => "$sandbox_home/msb_$version", query => 'show engines', expected => '!innodb\s*yes', msg => "single SB with option skip-innodb ($bare_version) SQL" }); ok_sql({ path => "$sandbox_home/msb_$version", query => q(show variables like 'SQL_MODE'), expected => 'STRICT_ALL_TABLES', msg => "single SB with option sql_mode ($bare_version) SQL " }); ok_sql({ path => "$sandbox_home/msb_$version", query => q(create database xyz; show databases like 'xyz'), expected => 'xyz', msg => "single SB ($bare_version) - create database" }); ok_exec({ command => "$sandbox_home/msb_$version/clear", expected => '!error', msg => "single SB ($bare_version) - clear result" }); # my $sandbox_dirs = get_exec_result("ls -d $sandbox_home/msb_$version/data/*/ | wc -l "); my $sandbox_dirs = how_many_dirs("$sandbox_home/msb_$version/data"); ok($sandbox_dirs == ($bare_version ge '5.5'? 3 : 2) , "single SB ($bare_version) - effective clear "); tprint "** cleaning up - please wait\n"; my $clear_all = get_exec_result("$sandbox_home/clear_all"); } sub get_bare_version { my ($ver) = @_; $ver =~ s{.*/}{}; if ($ver =~ /((?:\w+)?(\d+)\.(\d+)\.(\d+))/) { my $bv = $1; my $major = $2; my $minor = $3; my $rev = $4; my $underscored_version = $bv; $underscored_version =~ s/\./_/g; $bv =~ s/^\D+//; # print STDERR "$ver, $bv, $underscored_version \n"; exit; if (wantarray) { return ($bv, $underscored_version, $major, $minor, $rev); } else { return $bv; } } else { die "'$ver' does not contain a valid version\n"; } } sub run_smoke_test { my ($ver) = @_; if ($ver =~ /^[34]/) { tprint "skipping smoke test. It requires version >=5\n"; return; } my ($bare_version, $version) = get_bare_version($ver); $version =~ s/\./_/g; if ($ver =~ m{(.+)/[^/]+(?:tgz|tar\.gz)$}) { my $bindir = $1; if ( -d "$bindir/$bare_version" ) { system "rm -rf $bindir/$bare_version"; } } my $previous_mysqld = get_number_of_processes('mysqld'); my $previous_mysqld_safe = get_number_of_processes('mysqld_safe'); ok_exec({ command => "make_sandbox $ver -- --no_confirm", expected => 'sandbox server started', msg => "single SB ($bare_version) started" }); my $first_mysqld = get_number_of_processes('mysqld'); my $first_mysqld_safe = get_number_of_processes('mysqld_safe'); ok($first_mysqld_safe > $previous_mysqld_safe, 'mysqld_safe started') ; ok($first_mysqld > $previous_mysqld, 'mysqld started') ; my $sql_result = get_sql_result( "$sandbox_home/msb_$version", q{show variables like 'pid_file'}, $verbose); my $pid_file ; if ($sql_result =~ m{\s*(\S+\.pid)} ) { $pid_file = $1; } ok ($pid_file , 'pid_file found') or die "can't find pid file\n"; my $pid = get_pid($pid_file) or die "can't get PID from $pid_file\n" ; my $pid_ts1 = get_pid_timestamp($pid_file) or die "can't get timestamp for file $pid_file\n"; my $kill_result = get_exec_result("kill -9 $pid"); ok (! $kill_result, "mysqld killed"); my $timeout = 20; my $counter = 0; my $second_mysqld = 0; my $started ; while (! $started ) { $counter++; if ($counter >= $timeout) { last; } $second_mysqld = get_number_of_processes('mysqld'); $started = $second_mysqld >= $first_mysqld; unless ($started) { tprint "-- waiting for mysqld to restart ($counter)\n"; sleep 1; } } my $pid_ts2 = get_pid_timestamp($pid_file); $counter = 0; # print "PID_TS ==== $pid_ts1 $pid_ts2\n"; while ((!$pid_ts2) or ($pid_ts2 eq $pid_ts1)) { $counter++; tprint ">> waiting for mysqld to restart ($counter)\n"; sleep 1; $pid_ts2 = get_pid($pid_file); if ($counter > $timeout) { die "error recovering killed process\n"; } } ok ($second_mysqld >= $first_mysqld, "new mysqld process created (1)") ; my $secondpid = get_pid($pid_file) or die "can't get PID from $pid_file\n" ; chomp $secondpid; tprint "previous pid ($pid) current pid ($secondpid)\n" if $verbose; ok ($secondpid ne $pid, "new mysqld process created (2)"); ok_sql({ path => "$sandbox_home/msb_$version", query => 'select version()', expected => $bare_version, msg => "single SB ($bare_version) version (1)" }); my $visual_version ; ok_sql({ path => "$sandbox_home/msb_$version", query => q{show variables like 'version'}, expected => $bare_version, msg => "single SB ($bare_version) version (2)" }, \$visual_version); chomp $visual_version; $sql_result = get_sql_result( "$sandbox_home/msb_$version", 'select @@version_comment limit 1', $verbose ); my $visual_comment = $sql_result; chomp $visual_comment; $sql_result = get_sql_result( "$sandbox_home/msb_$version", 'HELP SELECT', $verbose ); # print "HELP: $sql_result\n"; ok( $sql_result && (! ( $sql_result =~ /nothing\s*found/i)), "single SB ($bare_version) HELP tables filled " ); ok_sql ({ path => "$sandbox_home/msb_$version", query => q(create database install_test; show databases like 'install_test'), expected => 'install_test', msg => "single SB ($bare_version) - create database" }); my @test_engines = ( { min_version => 5 , engine => 'innodb' }, #{ # min_version => 6 , # engine => 'innodb' #} ); for my $test_engine (@test_engines) { my $major_version = 0; if ($version =~ /(\d+)/) { $major_version = $1; } if ($major_version < $test_engine->{'min_version'} ) { next; } my $engine = $test_engine->{'engine'}; ok_sql ({ path => "$sandbox_home/msb_$version", query => qq{drop table if exists install_test.testib; create table install_test.testib ( id int UNSIGNED NOT NULL AUTO_INCREMENT , nr int UNSIGNED NOT NULL , PRIMARY KEY ( id) ) engine=$engine; show tables from install_test }, expected => 'testib', msg => "single SB ($bare_version) - create table" }); ok_sql ({ path => "$sandbox_home/msb_$version", query => q{select engine from information_schema.tables where table_schema='install_test' and table_name = 'testib' }, expected => $engine, msg => "single SB ($bare_version) - create table - check engine ($engine)" }); ok_sql ({ path => "$sandbox_home/msb_$version", query => q{alter table install_test.testib add index nr (nr); insert into install_test.testib(id,nr) values ( '1','1'); insert into install_test.testib(id,nr) values ( '2','2'); insert into install_test.testib(id,nr) values ( '3','2'); select * from install_test.testib where nr=2 order by id asc;}, expected => '2\t2\s*3\t2', msg => "smoke 1" }); } ok_sql ({ path => "$sandbox_home/msb_$version", query => q{select * from install_test.testib where nr=2 order by id desc;}, expected => '3\t2\s*2\t2', msg => "smoke 2" }); ok_sql ({ path => "$sandbox_home/msb_$version", query => q{select count(*) from install_test.testib}, expected => '^3$', msg => "rows in table" }); ok_sql ({ path => "$sandbox_home/msb_$version", query => q{truncate table install_test.testib;} . q{select count(*) from install_test.testib}, expected => '^0$', msg => "table truncation" }); ok_sql ({ path => "$sandbox_home/msb_$version", query => q{drop table install_test.testib;} . q{select count(*) from information_schema.tables } . q{where table_schema='install_test'}, expected => '^0$', msg => "tables in install_test " }); $sql_result = get_sql_result( "$sandbox_home/msb_$version", q{ drop database install_test;}, $verbose); my $sandbox_dirs = how_many_dirs("$sandbox_home/msb_$version/data"); my $expected_dirs = 2; if (greater_version( $bare_version, '5.7.7') && ( $bare_version !~ /^10/)) { $expected_dirs = 4; } elsif ($bare_version =~ /^10/) { $expected_dirs = 3; } elsif ($bare_version ge '5.5') { $expected_dirs = 3; } #ok($sandbox_dirs == ((($bare_version ge '5.5') or ($bare_version =~ /^10/)) ? 3 : 2) , "single SB ($bare_version) - effective clean up "); ok($sandbox_dirs == $expected_dirs, "single SB ($bare_version) - effective clean up "); tprint "** cleaning up - please wait\n"; my $clear = get_exec_result("$sandbox_home/msb_$version/clear"); if ($ver =~ m{(.+)/[^/]+(?:tgz|tar\.gz)$}) { my $bindir = $1; if ( -d "$bindir/$bare_version" ) { system "rm -rf $bindir/$bare_version"; system "rm -rf $sandbox_home/msb_$version"; } } tprint "\n[VISUAL IDENTIFICATION]\n"; tprint "\tcheck version: <$visual_version>\n"; tprint "\tcheck comment: <$visual_comment>\n\n"; } sub run_sbtool_test { my ($ver) = @_; # # preparing sandboxes # my $first_sandbox = get_exec_result( "make_sandbox $ver -- --no_confirm --sandbox_port=5100 --sandbox_directory=first_sb", $verbose); ok( $first_sandbox =~ /sandbox server started/, "first SB (5100) started" ); my $second_sandbox = get_exec_result( "make_sandbox $ver -- --no_confirm --sandbox_port=5200 --sandbox_directory=second_sb", $verbose); ok( $second_sandbox =~ /sandbox server started/, "second SB (5200) started" ); # # sbtool -o move # my $move_sandbox = get_exec_result("sbtool -o move -s $sandbox_home/first_sb -d $sandbox_home/xxx"); ok( $move_sandbox =~ /The old scripts have been saved/, 'first SB moved to xxx'); $first_sandbox = get_exec_result("$sandbox_home/xxx/start"); ok( $first_sandbox =~ /sandbox server started/, "moved sandbox started"); $move_sandbox = get_exec_result("sbtool -o move -d $sandbox_home/first_sb -s $sandbox_home/xxx"); ok( $move_sandbox =~ /The old scripts have been saved/, 'xxx moved back to first SB'); $first_sandbox = get_exec_result("$sandbox_home/first_sb/start"); ok( $first_sandbox =~ /sandbox server started/, "moved back sandbox started"); # # sbtool -o copy # my $sql_result = get_sql_result( "$sandbox_home/first_sb", q{drop table if exists test.t1; create table test.t1 (id int); show tables from test}, $verbose); ok( ($sql_result =~ /t1/) , "first SB - table created" ); my $copy_sandbox = get_exec_result("sbtool -o copy -s $sandbox_home/first_sb -d $sandbox_home/second_sb"); ok( $CHILD_ERROR == 0 , 'first SB copied to second SB'); $second_sandbox = get_exec_result("$sandbox_home/second_sb/start"); ok( $second_sandbox =~ /sandbox server started/, "copied sandbox started"); $sql_result = get_sql_result( "$sandbox_home/second_sb", q{show tables from test}, $verbose); ok( ($sql_result =~ /t1/) , "second SB - table copied" ); # # sbtool -o ports # my $get_ports = get_exec_result("sbtool -o ports"); ok ($get_ports =~ /5100\s+0/ && $get_ports =~ /5200\s+1/, 'get ports'); $get_ports = get_exec_result("sbtool --only_used -o ports"); ok ($get_ports !~ /5100\s+0/ && $get_ports =~ /5200\s+1/, 'get used ports'); $get_ports = get_exec_result("sbtool --format=perl -o ports"); # print $get_ports, "\n"; my $ports = undef; eval "$get_ports"; ok ( $ports && !$ports->{'5100'} && $ports->{'5200'}, 'get ports (perl format)'); # # sbtool -o info # my $get_info = get_exec_result("sbtool -o info"); my $all_info = undef; eval "$get_info"; ok($all_info && $all_info->{'5100'}{'opt'}{'port'} == 5100, 'get info 1'); ok($all_info && $all_info->{'5200'}{'opt'}{'port'} == 5200, 'get info 2'); # # sbtool -o port # (change port) # my $change_ports = get_exec_result("sbtool -o port --new_port=9000 -s $sandbox_home/first_sb"); ok( $change_ports =~ /The old scripts have been saved/, 'port changed to first SB'); $change_ports = get_exec_result("$sandbox_home/first_sb/start"); ok( $change_ports =~ /sandbox server started/, 'first SB restarted after port changed'); $sql_result = get_sql_result( "$sandbox_home/first_sb", q{show variables like 'port'}); ok($sql_result =~ /\b9000\b/, 'wanted port assigned to first SB'); # # sbtool -o range # my $ports_range = get_exec_result("sbtool -o range"); ok ($ports_range =~ /5010/, 'ports range'); $ports_range = get_exec_result("sbtool -o range -i 5200"); ok ($ports_range =~ /5201/, 'ports range 2'); system("$sandbox_home/stop_all > /dev/null 2>&1"); system("$sandbox_home/second_sb/start > /dev/null 2>&1"); # # sbtool -o delete # my $delete_sandbox = get_exec_result("sbtool -o delete -s $sandbox_home/first_sb"); ok($delete_sandbox =~ /has been removed/, 'delete stopped sandbox'); $delete_sandbox = get_exec_result("sbtool -o delete -s $sandbox_home/second_sb"); ok($delete_sandbox =~ /has been removed/, 'delete active sandbox'); $second_sandbox = get_exec_result( "make_sandbox $ver -- --no_confirm --sandbox_port=5200 --sandbox_directory=second_sb", $verbose); ok( $second_sandbox =~ /sandbox server started/, "second SB (5200) started" ); # # sbtool -o preserve # my $preserve_sandbox = get_exec_result("sbtool -o preserve -s $sandbox_home/second_sb"); ok($preserve_sandbox =~ /is now permanent/, 'preserve active sandbox'); $delete_sandbox = get_exec_result("sbtool -o delete -s $sandbox_home/second_sb"); ok($delete_sandbox =~ /can't be deleted/, '(not) deleting permanent sandbox'); my $unpreserve_sandbox = get_exec_result("sbtool -o unpreserve -s $sandbox_home/second_sb"); ok($unpreserve_sandbox =~ /is now NOT PERMANENT/, 'unpreserve active sandbox'); $delete_sandbox = get_exec_result("sbtool -o delete -s $sandbox_home/second_sb"); ok($delete_sandbox =~ /has been removed/, 'deleting unpreserved sandbox'); # # sbtool -o tree # my $group_sandbox = get_exec_result( "make_multiple_sandbox --group_directory=tree_sb --how_many_nodes=9 $ver", $verbose); ok( $group_sandbox =~ /installing node 9/, "group SB (node 9) installed" ); ok( $group_sandbox =~ /group directory installed/, "group SB installed" ); # workaround for MySQL 5.7.7 behavioral change with relay nodes #$sql_result = get_exec_result( # "$sandbox_home/tree_sb/use_all 'reset master'", # $verbose); my $tree_sandbox = get_exec_result("sbtool -o tree --tree_dir=$sandbox_home/tree_sb" . " --tree_nodes='1-2 3 4-5 6|7|8 9'" ); ok($tree_sandbox =~ 'node 1 is master', 'tree SB master'); ok($tree_sandbox =~ 'node 2 is slave of node 1', 'tree SB - level 1'); ok($tree_sandbox =~ 'node 7 is slave of node 3', 'tree SB - level 2'); $sql_result = get_sql_result( "$sandbox_home/tree_sb/node1", q{drop table if exists test.t1; create table test.t1 (id int); show tables from test}, $verbose); ok( ($sql_result =~ /t1/) , "tree SB - table created" ); sleep 1; $sql_result = get_sql_result( "$sandbox_home/tree_sb/node8", q{show tables from test}, $verbose); #print "$sql_result\n"; ok( ($sql_result =~ /t1/) , "tree SB - table replicated to level 3" ); system("$sandbox_home/send_kill_all > /dev/null 2>&1"); system("$sandbox_home/clear_all > /dev/null 2>&1"); } sub get_pid { my ($pfile) = @_; my $timeout = 5; my $counter = 0; my $PFILE; while (! $PFILE) { eval { open( $PFILE, q{<}, $pfile) or die; }; next if $@; last if $PFILE; if ($counter >= $timeout) { die "can't open $pfile\n"; } else { sleep 1; } $counter++; } print Dumper $PFILE if $verbose; die "can't open $pfile\n" unless $PFILE; my $pid = <$PFILE>; close $PFILE; chomp $pid if $pid; if ($pid && ($pid =~ /^\d+$/) ) { return $pid; } return 0; } sub get_pid_timestamp { my ($pidfile) = @_; my @stats = stat $pidfile or return 0; # or die "can't get timestamp for file $pidfile ($!)\n"; return $stats[8]; } sub how_many_dirs { my ($path) = @_; my @subdirs = glob("$path/*/"); my $dir_count =0; # warn Dumper \@subdirs; for (@subdirs) { $dir_count++ if -d $_; } return $dir_count; } sub exists_in_path { my ($fname) = @_; my @paths = split /:/, $ENV{'PATH'}; for my $path (@paths) { $path =~ s{/$}{}; if ( -f "$path/$fname") { return 1; } } return 0; } sub tprint { unless ($ENV{'TAP_MODE'}) { print @_; } } sub tprintf { unless ($ENV{'TAP_MODE'}) { printf @_; } } sub run_user_defined_test { my ($test_file) = @_; if ($test_file =~ /\.sb\.pl$/) { return run_user_defined_perl_test($test_file); } my %test_structs = ( shell => {required => [qw(command expected msg)], rec => undef}, sql => {required => [qw(path query expected msg)], rec => undef}, ); my @user_tests = (); my $current_struct = undef; open my $TFILE, q{<}, $test_file or die "can't open $test_file ($!)\n"; while (my $line = <$TFILE>) { next if $line =~ /^\s*$/; next if $line =~ /^\s*#/; chomp($line); if ($line =~ /(\w+):/) { my $struct = $1; unless ($test_structs{$struct}) { die "unrecognized test type\n" } if ($current_struct) { my %rec = %{$test_structs{$current_struct}{rec}}; push @user_tests, [$current_struct,\%rec]; $test_structs{$current_struct}{rec} = undef; } $current_struct = $struct; } elsif ( $line =~ /(\w+)\s*=\s*(.*)/ ) { my $key = $1; my $value = $2; $value =~ s/\$(\w+)/$ENV{$1}/g; $test_structs{$current_struct}{rec}{$key} = $value; } else { die "error parsing line <$.> at file <$test_file>\n"; } } close $TFILE; if ($current_struct) { my %rec = %{$test_structs{$current_struct}{rec}}; push @user_tests, [$current_struct,\%rec]; $test_structs{$current_struct}{rec} = undef; } for my $test (@user_tests) { for my $req (@{ $test_structs{$test->[0]}{required}}) { unless (defined $test->[1]{$req}) { for my $key (keys %{ $test->[1] } ) { tprintf "%20s => %s\n", $key, $test->[1]{$key}; } die "incomplete test. Missing required <$req> label\n"; } } } # print Dumper \@user_tests; exit; for my $test (@user_tests) { my $rec = $test->[1]; # print Dumper $test; if ($test->[0] eq 'shell') { ok_exec({ command => $rec->{command}, expected => $rec->{expected}, msg => $rec->{msg}, }); } elsif ($test->[0] eq 'sql') { ok_sql({ path => $rec->{path}, query => $rec->{query}, expected => $rec->{expected}, msg => $rec->{msg}, }); } else { die "unhandled test <$test->[0]>\n"; } } } sub run_user_defined_perl_test { my ($test_file) = @_; open my $FH, q{<}, $test_file or die "can't open $test_file ($!)\n"; my $test_contents =''; while (my $line = <$FH>) { $test_contents .= $line; } close ($FH); eval $test_contents; if ($@) { die "failed test $test_file\n$@\n"; } }