From 54e418184abcc9836e68cba9138a5c3b6fe82733 Mon Sep 17 00:00:00 2001 From: gau1991 Date: Mon, 2 Mar 2015 18:04:26 +0530 Subject: [PATCH] Added stack migrate command to migrate MySQL/Percona to MariaDB --- ee/cli/plugins/stack.py | 2 + ee/cli/plugins/stack_migrate.py | 99 +++++++++++++++++++++++++++++++++ ee/core/mysql.py | 43 +++++++++++++- 3 files changed, 141 insertions(+), 3 deletions(-) create mode 100644 ee/cli/plugins/stack_migrate.py diff --git a/ee/cli/plugins/stack.py b/ee/cli/plugins/stack.py index e0a24349..54a6fbb6 100644 --- a/ee/cli/plugins/stack.py +++ b/ee/cli/plugins/stack.py @@ -26,6 +26,7 @@ import pwd import grp import codecs from ee.cli.plugins.stack_services import EEStackStatusController +from ee.cli.plugins.stack_migrate import EEStackMigrateController from ee.core.logging import Log @@ -1523,6 +1524,7 @@ def load(app): # register the plugin class.. this only happens if the plugin is enabled handler.register(EEStackController) handler.register(EEStackStatusController) + handler.register(EEStackMigrateController) # register a hook (function) to run after arguments are parsed. hook.register('post_argument_parsing', ee_stack_hook) diff --git a/ee/cli/plugins/stack_migrate.py b/ee/cli/plugins/stack_migrate.py new file mode 100644 index 00000000..2e4becf4 --- /dev/null +++ b/ee/cli/plugins/stack_migrate.py @@ -0,0 +1,99 @@ +from cement.core.controller import CementBaseController, expose +from cement.core import handler, hook +from ee.core.mysql import EEMysql +from ee.core.logging import Log +from ee.core.variables import EEVariables +from ee.core.aptget import EEAptGet +from ee.core.shellexec import EEShellExec +from ee.core.apt_repo import EERepo +import configparser +import os + + +class EEStackMigrateController(CementBaseController): + class Meta: + label = 'migrate' + stacked_on = 'stack' + stacked_type = 'nested' + description = ('Migrate stack safely') + arguments = [ + (['--mariadb'], + dict(help="Migrate database to MariaDB", + action='store_true')), + # (['--PHP'], + # dict(help="update to html site", action='store_true')), + ] + + @expose(hide=True) + def migrate_mariadb(self): + # Backup all database + EEMysql.backupAll(self) + + # Add MariaDB repo + Log.info(self, "Adding repository for MariaDB, please wait ...") + EERepo.add(self, repo_url=EEVariables.ee_mysql_repo) + Log.debug(self, 'Adding key for {0}' + .format(EEVariables.ee_mysql_repo)) + EERepo.add_key(self, '0xcbcb082a1bb943db', + keyserver="keyserver.ubuntu.com") + + config = configparser.ConfigParser() + config.read(os.path.expanduser("~")+'/.my.cnf') + try: + chars = config['client']['password'] + except Exception as e: + Log.error(self, "Error: process exited with error %s" + % e) + + Log.debug(self, "Pre-seeding MariaDB") + Log.debug(self, "echo \"mariadb-server-10.0 " + "mysql-server/root_password " + "password \" | " + "debconf-set-selections") + EEShellExec.cmd_exec(self, "echo \"mariadb-server-10.0 " + "mysql-server/root_password " + "password {chars}\" | " + "debconf-set-selections" + .format(chars=chars), + log=False) + Log.debug(self, "echo \"mariadb-server-10.0 " + "mysql-server/root_password_again " + "password \" | " + "debconf-set-selections") + EEShellExec.cmd_exec(self, "echo \"mariadb-server-10.0 " + "mysql-server/root_password_again " + "password {chars}\" | " + "debconf-set-selections" + .format(chars=chars), + log=False) + + # Install MariaDB + apt_packages = EEVariables.ee_mysql + Log.info(self, "Updating apt-cache, please wait ...") + EEAptGet.update(self) + Log.info(self, "Installing MariaDB, please wait ...") + EEAptGet.install(self, apt_packages) + + @expose(hide=True) + def default(self): + if ((not self.app.pargs.mariadb)): + self.app.args.print_help() + if self.app.pargs.mariadb: + if EEVariables.ee_mysql_host is not "localhost": + Log.error(self, "Remote MySQL found, EasyEngine will not " + "install MariaDB") + + if EEShellExec.cmd_exec(self, "mysqladmin ping") and (not + EEAptGet.is_installed(self, 'mariadb-server')): + + Log.info(self, "If your database size is big, " + "migration may take some time.") + Log.info(self, "During migration non nginx-cached parts of " + "your site may remain down") + start_migrate = input("Type \"mariadb\" to continue:") + if start_migrate != "mariadb": + Log.error(self, "Not starting migration") + self.migrate_mariadb() + else: + Log.error(self, "Your current MySQL is not alive or " + "you allready installed MariaDB") diff --git a/ee/core/mysql.py b/ee/core/mysql.py index daf10aec..3ae821fb 100644 --- a/ee/core/mysql.py +++ b/ee/core/mysql.py @@ -3,7 +3,9 @@ import pymysql import configparser from os.path import expanduser import sys +import os from ee.core.logging import Log +from ee.core.variables import EEVariables class EEMysql(): @@ -60,7 +62,42 @@ class EEMysql(): else: Log.error(self, '{0}'.format(errormsg)) + def backupAll(self): + import subprocess + try: + Log.info(self, "Backing up database at location: " + "/var/ee-mysqlbackup") + # Setup Nginx common directory + if not os.path.exists('/var/ee-mysqlbackup'): + Log.debug(self, 'Creating directory' + '/var/ee-mysqlbackup') + os.makedirs('/var/ee-mysqlbackup') -# def __del__(self): -# self.cur.close() -# self.conn.close() + db = subprocess.check_output(["mysql -Bse \'show databases\'"], + universal_newlines=True, + shell=True).split('\n') + for dbs in db: + if dbs == "": + continue + Log.info(self, "Backing up {0} database".format(dbs)) + p1 = subprocess.Popen("mysqldump {0}" + " --max_allowed_packet=1024M" + " --single-transaction".format(dbs), + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, shell=True) + p2 = subprocess.Popen("gzip -c > /var/ee-mysqlbackup/{0}{1}.s" + "ql.gz".format(dbs, EEVariables.ee_date), + stdin=p1.stdout, + shell=True) + + # Allow p1 to receive a SIGPIPE if p2 exits + p1.stdout.close() + output = p1.stderr.read() + + if output == b'': + Log.debug(self, "done") + else: + Log.error(self, output) + except Exception as e: + Log.error(self, "Error: process exited with status %s" + % e)