Merge "Fixed MySQL 5.7 not starting after restore"

This commit is contained in:
Jenkins 2017-04-26 18:14:22 +00:00 committed by Gerrit Code Review
commit b0a45c0962

View File

@ -39,19 +39,12 @@ class MySQLRestoreMixin(object):
RESET_ROOT_RETRY_TIMEOUT = 100 RESET_ROOT_RETRY_TIMEOUT = 100
RESET_ROOT_SLEEP_INTERVAL = 10 RESET_ROOT_SLEEP_INTERVAL = 10
# Reset the root password in a single transaction with 'FLUSH PRIVILEGES' RESET_ROOT_MYSQL_COMMANDS = ("SET PASSWORD FOR "
# to ensure we never leave database wide open without 'grant tables'. "'root'@'localhost'=PASSWORD('');")
RESET_ROOT_MYSQL_COMMANDS = ("START TRANSACTION;",
"UPDATE `mysql`.`user` SET"
" `password`=PASSWORD('')"
" WHERE `user`='root'"
" AND `host` = 'localhost';",
"FLUSH PRIVILEGES;",
"COMMIT;")
# This is a suffix MySQL appends to the file name given in # This is a suffix MySQL appends to the file name given in
# the '--log-error' startup parameter. # the '--log-error' startup parameter.
_ERROR_LOG_SUFFIX = '.err' _ERROR_LOG_SUFFIX = '.err'
_ERROR_MESSAGE_PATTERN = re.compile("^ERROR:\s+.+$") _ERROR_MESSAGE_PATTERN = re.compile("ERROR")
def mysql_is_running(self): def mysql_is_running(self):
try: try:
@ -80,16 +73,12 @@ class MySQLRestoreMixin(object):
raise exc raise exc
def _start_mysqld_safe_with_init_file(self, init_file, err_log_file): def _start_mysqld_safe_with_init_file(self, init_file, err_log_file):
child = pexpect.spawn("sudo mysqld_safe" child = pexpect.spawn(
" --skip-grant-tables" "sudo mysqld_safe --init-file=%s --log-error=%s" %
" --skip-networking" (init_file.name, err_log_file.name))
" --init-file='%s'"
" --log-error='%s'" %
(init_file.name, err_log_file.name)
)
try: try:
i = child.expect(['Starting mysqld daemon']) index = child.expect(['Starting mysqld daemon'])
if i == 0: if index == 0:
LOG.info(_("Starting MySQL")) LOG.info(_("Starting MySQL"))
except pexpect.TIMEOUT: except pexpect.TIMEOUT:
LOG.exception(_("Got a timeout launching mysqld_safe")) LOG.exception(_("Got a timeout launching mysqld_safe"))
@ -110,7 +99,8 @@ class MySQLRestoreMixin(object):
LOG.info(_("Root password reset successfully.")) LOG.info(_("Root password reset successfully."))
LOG.debug("Cleaning up the temp mysqld process.") LOG.debug("Cleaning up the temp mysqld process.")
utils.execute_with_timeout("mysqladmin", "-uroot", "shutdown") utils.execute_with_timeout("mysqladmin", "-uroot",
"--protocol=tcp", "shutdown")
LOG.debug("Polling for shutdown to complete.") LOG.debug("Polling for shutdown to complete.")
try: try:
utils.poll_until(self.mysql_is_not_running, utils.poll_until(self.mysql_is_not_running,
@ -134,10 +124,10 @@ class MySQLRestoreMixin(object):
""" """
with tempfile.NamedTemporaryFile(mode='w') as init_file: with tempfile.NamedTemporaryFile(mode='w') as init_file:
operating_system.write_file(init_file.name,
self.RESET_ROOT_MYSQL_COMMANDS)
operating_system.chmod(init_file.name, FileMode.ADD_READ_ALL, operating_system.chmod(init_file.name, FileMode.ADD_READ_ALL,
as_root=True) as_root=True)
self._writelines_one_per_line(init_file,
self.RESET_ROOT_MYSQL_COMMANDS)
# Do not attempt to delete the file as the 'trove' user. # Do not attempt to delete the file as the 'trove' user.
# The process writing into it may have assumed its ownership. # The process writing into it may have assumed its ownership.
# Only owners can delete temporary # Only owners can delete temporary
@ -149,38 +139,19 @@ class MySQLRestoreMixin(object):
self._start_mysqld_safe_with_init_file(init_file, err_log_file) self._start_mysqld_safe_with_init_file(init_file, err_log_file)
finally: finally:
err_log_file.close() err_log_file.close()
MySQLRestoreMixin._delete_file(err_log_file.name) operating_system.remove(
err_log_file.name, force=True, as_root=True)
def _writelines_one_per_line(self, fp, lines):
fp.write(os.linesep.join(lines))
fp.flush()
def _find_first_error_message(self, fp): def _find_first_error_message(self, fp):
if MySQLRestoreMixin._is_non_zero_file(fp): if self._is_non_zero_file(fp):
return MySQLRestoreMixin._find_first_pattern_match( return self._find_first_pattern_match(
fp, fp, self._ERROR_MESSAGE_PATTERN)
self._ERROR_MESSAGE_PATTERN
)
return None return None
@classmethod
def _delete_file(self, file_path):
"""Force-remove a given file as root.
Do not raise an exception on failure.
"""
if os.path.isfile(file_path):
try:
operating_system.remove(file_path, force=True, as_root=True)
except Exception:
LOG.exception(_("Could not remove file: '%s'") % file_path)
@classmethod
def _is_non_zero_file(self, fp): def _is_non_zero_file(self, fp):
file_path = fp.name file_path = fp.name
return os.path.isfile(file_path) and (os.path.getsize(file_path) > 0) return os.path.isfile(file_path) and (os.path.getsize(file_path) > 0)
@classmethod
def _find_first_pattern_match(self, fp, pattern): def _find_first_pattern_match(self, fp, pattern):
for line in fp: for line in fp:
if pattern.match(line): if pattern.match(line):