<commit_before># Copyright 2013 Hewlett-Packard Development Company, L.P.
# All Rights Reserved.
#
#    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.
#

import glob
import os
import pexpect
import tempfile

from trove.guestagent.strategies.restore import base
from trove.openstack.common import log as logging
from trove.common import exception
from trove.common import utils
import trove.guestagent.datastore.mysql.service as dbaas
from trove.openstack.common.gettextutils import _  # noqa

LOG = logging.getLogger(__name__)


class MySQLRestoreMixin(object):
    """Common utils for restoring MySQL databases."""
    RESET_ROOT_RETRY_TIMEOUT = 100
    RESET_ROOT_SLEEP_INTERVAL = 10
    RESET_ROOT_MYSQL_COMMAND = ("SET PASSWORD FOR"
                                "'root'@'localhost'=PASSWORD('');")

    def mysql_is_running(self):
        if base.exec_with_root_helper("/usr/bin/mysqladmin", "ping"):
            LOG.debug("MySQL is up and running.")
            return True
        else:
            LOG.debug("MySQL is not running.")
            return False

    def mysql_is_not_running(self):
        if base.exec_with_root_helper("/usr/bin/pgrep", "mysqld"):
            LOG.info("MySQL is still running.")
            return False
        else:
            LOG.debug("MySQL is not running.")
            return True

    def poll_until_then_raise(self, event, exc):
        try:
            utils.poll_until(event,
                             sleep_time=self.RESET_ROOT_SLEEP_INTERVAL,
                             time_out=self.RESET_ROOT_RETRY_TIMEOUT)
        except exception.PollTimeOut:
            raise exc

    def _spawn_with_init_file(self, temp_file):
        child = pexpect.spawn("sudo mysqld_safe --init-file=%s" %
                              temp_file.name)
        try:
            i = child.expect(['Starting mysqld daemon'])
            if i == 0:
                LOG.info(_("Starting MySQL"))
        except pexpect.TIMEOUT:
            LOG.exception(_("Got a timeout launching mysqld_safe"))
        finally:
            # There is a race condition here where we kill mysqld before
            # the init file been executed. We need to ensure mysqld is up.
            self.poll_until_then_raise(
                self.mysql_is_running,
                base.RestoreError("Reset root password failed: "
                                  "mysqld did not start!"))
            LOG.info(_("Root password reset successfully."))
            LOG.debug("Cleaning up the temp mysqld process.")
            child.delayafterclose = 1
            child.delayafterterminate = 1
            child.close(force=True)
            utils.execute_with_timeout("sudo", "killall", "mysqld")
            self.poll_until_then_raise(
                self.mysql_is_not_running,
                base.RestoreError("Reset root password failed: "
                                  "mysqld did not stop!"))

    def reset_root_password(self):
        #Create temp file with reset root password
        with tempfile.NamedTemporaryFile() as fp:
            fp.write(self.RESET_ROOT_MYSQL_COMMAND)
            fp.flush()
            utils.execute_with_timeout("sudo", "chmod", "a+r", fp.name)
            self._spawn_with_init_file(fp)


class MySQLDump(base.RestoreRunner, MySQLRestoreMixin):
    """Implementation of Restore Strategy for MySQLDump."""
    __strategy_name__ = 'mysqldump'
    base_restore_cmd = 'sudo mysql'


class InnoBackupEx(base.RestoreRunner, MySQLRestoreMixin):
    """Implementation of Restore Strategy for InnoBackupEx."""
    __strategy_name__ = 'innobackupex'
    base_restore_cmd = 'sudo xbstream -x -C %(restore_location)s'<commit_msg>Fixed restore to work correctly with pexpect<commit_after># Copyright 2013 Hewlett-Packard Development Company, L.P.
# All Rights Reserved.
#
#    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.
#

import glob
import os
import pexpect
import tempfile

from trove.guestagent.strategies.restore import base
from trove.openstack.common import log as logging
from trove.common import exception
from trove.common import utils
import trove.guestagent.datastore.mysql.service as dbaas
from trove.openstack.common.gettextutils import _  # noqa

LOG = logging.getLogger(__name__)


class MySQLRestoreMixin(object):
    """Common utils for restoring MySQL databases."""
    RESET_ROOT_RETRY_TIMEOUT = 100
    RESET_ROOT_SLEEP_INTERVAL = 10
    RESET_ROOT_MYSQL_COMMAND = ("SET PASSWORD FOR"
                                "'root'@'localhost'=PASSWORD('');")

    def mysql_is_running(self):
        if base.exec_with_root_helper("/usr/bin/mysqladmin", "ping"):
            LOG.debug("MySQL is up and running.")
            return True
        else:
            LOG.debug("MySQL is not running.")
            return False

    def mysql_is_not_running(self):
        if base.exec_with_root_helper("/usr/bin/pgrep", "mysqld"):
            LOG.info("MySQL is still running.")
            return False
        else:
            LOG.debug("MySQL is not running.")
            return True

    def poll_until_then_raise(self, event, exc):
        try:
            utils.poll_until(event,
                             sleep_time=self.RESET_ROOT_SLEEP_INTERVAL,
                             time_out=self.RESET_ROOT_RETRY_TIMEOUT)
        except exception.PollTimeOut:
            raise exc

    def _spawn_with_init_file(self, temp_file):
        child = pexpect.spawn("sudo mysqld_safe --init-file=%s" %
                              temp_file.name)
        try:
            i = child.expect(['Starting mysqld daemon'])
            if i == 0:
                LOG.info(_("Starting MySQL"))
        except pexpect.TIMEOUT:
            LOG.exception(_("Got a timeout launching mysqld_safe"))
        finally:
            # There is a race condition here where we kill mysqld before
            # the init file been executed. We need to ensure mysqld is up.
            self.poll_until_then_raise(
                self.mysql_is_running,
                base.RestoreError("Reset root password failed: "
                                  "mysqld did not start!"))
            LOG.info(_("Root password reset successfully."))
            LOG.debug("Cleaning up the temp mysqld process.")
            utils.execute_with_timeout("mysqladmin", "-uroot",
                                       "--protocol=tcp", "shutdown")
            utils.execute_with_timeout("killall", "mysqld_safe",
                                       root_helper="sudo", run_as_root=True)
            self.poll_until_then_raise(
                self.mysql_is_not_running,
                base.RestoreError("Reset root password failed: "
                                  "mysqld did not stop!"))

    def reset_root_password(self):
        #Create temp file with reset root password
        with tempfile.NamedTemporaryFile() as fp:
            fp.write(self.RESET_ROOT_MYSQL_COMMAND)
            fp.flush()
            utils.execute_with_timeout("sudo", "chmod", "a+r", fp.name)
            self._spawn_with_init_file(fp)


class MySQLDump(base.RestoreRunner, MySQLRestoreMixin):
    """Implementation of Restore Strategy for MySQLDump."""
    __strategy_name__ = 'mysqldump'
    base_restore_cmd = 'sudo mysql'


class InnoBackupEx(base.RestoreRunner, MySQLRestoreMixin):
    """Implementation of Restore Strategy for InnoBackupEx."""
    __strategy_name__ = 'innobackupex'
    base_restore_cmd = 'sudo xbstream -x -C %(restore_location)s'
{'fraction_non_alphanumeric': 0.08457828490765792, 'fraction_numerical': 0.003528996588636631, 'mean_word_length': 2.3315047021943576, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 3, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 8, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '129027', 'n_tokens_mistral': 2438, 'n_tokens_neox': 2356, 'n_words': 661}