Пример #1
0
    def __init__(self, orig_master_host, orig_master_ip, orig_master_ssh_port,
            new_master_host, new_master_ip, new_master_ssh_port, 
            ssh_options, privileged_users):
        self._orig_master_config_helper = MHA_config_helper(host=orig_master_host)
        self._new_master_config_helper = MHA_config_helper(host=new_master_host)

        self._orig_master = MySQL_helper(host=orig_master_ip, 
                                        user=self._orig_master_config_helper.get_mysql_user(), 
                                        password=self._orig_master_config_helper.get_mysql_password())

        self._new_master = MySQL_helper(host=new_master_ip, 
                                        user=self._new_master_config_helper.get_mysql_user(), 
                                        password=self._new_master_config_helper.get_mysql_password())

        self._orig_master_ip = orig_master_ip

        if orig_master_ssh_port is None:
            self._orig_master_ssh_port = 22
        else:
            self._orig_master_ssh_port = orig_master_ssh_port

        self._new_master_ip = new_master_ip

        if new_master_ssh_port is None:
            self._new_master_ssh_port = 22
        else:
            self._new_master_ssh_port = new_master_ssh_port

        self._ssh_options = ssh_options

        self._privileged_users = privileged_users
	self._user_grants_orig_master = []
Пример #2
0
    def __init__(self, slave_host):
        self._slave_host_config_helper = MHA_config_helper(host=slave_host)

        self._slave_hostname = slave_host

        mysql_user = self._slave_host_config_helper.get_mysql_user()
        mysql_password = self._slave_host_config_helper.get_mysql_password()
        host_ip = self._slave_host_config_helper.get_host_ip()

        self._slave_host = MySQL_helper(host=host_ip, user=mysql_user,
                            password=mysql_password) 
Пример #3
0
    def execute_status_command(self, orig_master_host, orig_master_ip,
                               ssh_user, ssh_options, ssh_port):
        config_helper = MHA_config_helper(host=orig_master_host)

        if ssh_port is None:
            ssh_port = 22

        self.debug_message("Doing sanity checks")

        mysql_user = config_helper.get_mysql_user()
        mysql_password = config_helper.get_mysql_password()

        if mysql_user == False or mysql_password == False:
            self.debug_message("Error accessing MySQL credentials from config")
            return MHA_IP_failover_helper.CODE_ERR_GENERAL

        if config_helper.get_manage_vip() == True:
            cluster_interface = config_helper.get_cluster_interface()
            writer_vip_cidr = config_helper.get_writer_vip_cidr()

            if cluster_interface == False or writer_vip_cidr == False:
                self.debug_message("Error fetching cluster_interface and "
                                   "writer_vip_cidr from config")
                return MHA_IP_failover_helper.CODE_ERR_GENERAL

        return MHA_IP_failover_helper.CODE_SUCCESS
Пример #4
0
    def __init__(self, slave_host):
        self._slave_host_config_helper = MHA_config_helper(host=slave_host)

        self._slave_hostname = slave_host

        mysql_user = self._slave_host_config_helper.get_mysql_user()
        mysql_password = self._slave_host_config_helper.get_mysql_password()
        host_ip = self._slave_host_config_helper.get_host_ip()

        self._slave_host = MySQL_helper(host=host_ip, user=mysql_user, password=mysql_password)
    def execute_status_command(self, orig_master_host, orig_master_ip, 
                                ssh_user, ssh_options, ssh_port):
        config_helper = MHA_config_helper(host=orig_master_host)

        if ssh_port is None:
            ssh_port = 22

        self.debug_message("Doing sanity checks")

        mysql_user = config_helper.get_mysql_user()
        mysql_password = config_helper.get_mysql_password()

        if mysql_user == False or mysql_password == False:
            self.debug_message("Error accessing MySQL credentials from config")
            return MHA_IP_failover_helper.CODE_ERR_GENERAL

        if config_helper.get_manage_vip() == True:
            cluster_interface = config_helper.get_cluster_interface()
            writer_vip_cidr = config_helper.get_writer_vip_cidr()

            if cluster_interface == False or writer_vip_cidr == False:
                self.debug_message("Error fetching cluster_interface and "
                    "writer_vip_cidr from config")
                return MHA_IP_failover_helper.CODE_ERR_GENERAL

        return MHA_IP_failover_helper.CODE_SUCCESS
    def execute_start_command(self, orig_master_host, orig_master_ip, 
                                new_master_host, new_master_ip, new_master_port,
                                ssh_user, ssh_options, ssh_port):
        config_helper = MHA_config_helper(host=new_master_host)
        
        new_master = MySQL_helper(host=new_master_ip, 
                                    user=config_helper.get_mysql_user(),
                                    password=config_helper.get_mysql_password(),
                                    port=new_master_port)

        if ssh_port is None:
            ssh_port = 22

        # Connect to the new master
        if new_master.connect() == False:
            return MHA_IP_failover_helper.CODE_ERR_GENERAL

        # If we have to manage the VIP, then assign the VIP to the new master
        if config_helper.get_manage_vip() == True:
            return_val = MHA_VIP_helper.assign_vip(config_helper=config_helper,
                                                host_ip=new_master_ip,
                                                ssh_user=ssh_user,
                                                ssh_port=ssh_port,
                                                ssh_options=ssh_options)

        if return_val == False:
            new_master.disconnect()
            return MHA_IP_failover_helper.CODE_ERR_GENERAL

        # Remove the read_only flag
        self.debug_message("Removing the read_only flag from the new master")
        new_master.unset_read_only()

        # Disconnect from the new master
        new_master.disconnect()

        return MHA_IP_failover_helper.CODE_SUCCESS
    def execute_stopssh_command(self, orig_master_host, orig_master_ip, 
                                ssh_user, ssh_options, ssh_port):
        config_helper = MHA_config_helper(host=orig_master_host)

        #orig_master = MySQL_helper(host=orig_master_ip, 
        #                            user=config_helper.get_mysql_user(),
        #                            password=config_helper.get_mysql_password())

        if ssh_port is None:
            ssh_port = 22

        # If we have to manage the VIP, then remove the VIP from the original master
        if config_helper.get_manage_vip() == True:
            return_val = MHA_VIP_helper.remove_vip(config_helper=config_helper,
                                                host_ip=orig_master_ip,
                                                ssh_user=ssh_user,
                                                ssh_port=ssh_port,
                                                ssh_options=ssh_options)
        if return_val == True:
            exit_code = MHA_IP_failover_helper.CODE_SUCCESS
        else:
            exit_code = MHA_IP_failover_helper.CODE_ERR_GENERAL

        return exit_code
Пример #8
0
    def execute_start_command(self, orig_master_host, orig_master_ip,
                              new_master_host, new_master_ip, ssh_user,
                              ssh_options, ssh_port):
        config_helper = MHA_config_helper(host=new_master_host)

        new_master = MySQL_helper(host=new_master_ip,
                                  user=config_helper.get_mysql_user(),
                                  password=config_helper.get_mysql_password())

        if ssh_port is None:
            ssh_port = 22

        # Connect to the new master
        if new_master.connect() == False:
            return MHA_IP_failover_helper.CODE_ERR_GENERAL

        # If we have to manage the VIP, then assign the VIP to the new master
        if config_helper.get_manage_vip() == True:
            return_val = MHA_VIP_helper.assign_vip(config_helper=config_helper,
                                                   host_ip=new_master_ip,
                                                   ssh_user=ssh_user,
                                                   ssh_port=ssh_port,
                                                   ssh_options=ssh_options)

        if return_val == False:
            new_master.disconnect()
            return MHA_IP_failover_helper.CODE_ERR_GENERAL

        # Remove the read_only flag
        self.debug_message("Removing the read_only flag from the new master")
        new_master.unset_read_only()

        # Disconnect from the new master
        new_master.disconnect()

        return MHA_IP_failover_helper.CODE_SUCCESS
Пример #9
0
    def execute_stopssh_command(self, orig_master_host, orig_master_ip,
                                ssh_user, ssh_options, ssh_port):
        config_helper = MHA_config_helper(host=orig_master_host)

        orig_master = MySQL_helper(host=orig_master_ip,
                                   user=config_helper.get_mysql_user(),
                                   password=config_helper.get_mysql_password())

        if ssh_port is None:
            ssh_port = 22

        # If we have to manage the VIP, then remove the VIP from the original master
        if config_helper.get_manage_vip() == True:
            return_val = MHA_VIP_helper.remove_vip(config_helper=config_helper,
                                                   host_ip=orig_master_ip,
                                                   ssh_user=ssh_user,
                                                   ssh_port=ssh_port,
                                                   ssh_options=ssh_options)
        if return_val == True:
            exit_code = MHA_IP_failover_helper.CODE_SUCCESS
        else:
            exit_code = MHA_IP_failover_helper.CODE_ERR_GENERAL

        return exit_code
    def __init__(self, orig_master_host, orig_master_ip, orig_master_ssh_port,
                 new_master_host, new_master_ip, new_master_ssh_port,
                 ssh_options, privileged_users):
        self._orig_master_config_helper = MHA_config_helper(
            host=orig_master_host)
        self._new_master_config_helper = MHA_config_helper(
            host=new_master_host)

        self._orig_master = MySQL_helper(
            host=orig_master_ip,
            user=self._orig_master_config_helper.get_mysql_user(),
            password=self._orig_master_config_helper.get_mysql_password())

        self._new_master = MySQL_helper(
            host=new_master_ip,
            user=self._new_master_config_helper.get_mysql_user(),
            password=self._new_master_config_helper.get_mysql_password())

        self._orig_master_ip = orig_master_ip

        if orig_master_ssh_port is None:
            self._orig_master_ssh_port = 22
        else:
            self._orig_master_ssh_port = orig_master_ssh_port

        self._new_master_ip = new_master_ip

        if new_master_ssh_port is None:
            self._new_master_ssh_port = 22
        else:
            self._new_master_ssh_port = new_master_ssh_port

        self._ssh_options = ssh_options

        self._privileged_users = privileged_users
        self._user_grants_orig_master = []
Пример #11
0
class MHA_slave_helper(object):
    CODE_SUCCESS = 0
    CODE_ERR_MYSQL_CONN = 1
    CODE_ERR_READ_ONLY = 10
    CODE_ERR_SLAVE_RUNNING = 20
    CODE_ERR_SLAVE_LAG = 30

    def __init__(self, slave_host):
        self._slave_host_config_helper = MHA_config_helper(host=slave_host)

        self._slave_hostname = slave_host

        mysql_user = self._slave_host_config_helper.get_mysql_user()
        mysql_password = self._slave_host_config_helper.get_mysql_password()
        host_ip = self._slave_host_config_helper.get_host_ip()

        self._slave_host = MySQL_helper(host=host_ip, user=mysql_user, password=mysql_password)

    def is_healthy(self):
        # Try to connect to the slave
        if self._slave_host.connect() == False:
            return MHA_slave_helper.CODE_ERR_MYSQL_CONN

        slave_status = self._slave_host.get_slave_status()
        # If we get an empty slave status that means that this is a master
        # If we get a FALSE result that means there was an error running
        # the query
        if slave_status == False or slave_status is None:
            return MHA_slave_helper.CODE_ERR_SLAVE_RUNNING

        # Check if slave threads are running
        if slave_status["Slave_IO_Running"] != "Yes" or slave_status["Slave_SQL_Running"] != "Yes":
            return MHA_slave_helper.CODE_ERR_SLAVE_RUNNING

        # Check if slave lag is within the allowable threshold
        slave_lag_threshold = self._slave_host_config_helper.get_slave_lag_threshold()
        current_slave_lag = slave_status["Seconds_Behind_Master"]
        if current_slave_lag is None or int(current_slave_lag) > slave_lag_threshold:
            return MHA_slave_helper.CODE_ERR_SLAVE_LAG

        # Check if read_only flag is set
        if self._slave_host.is_read_only() == False:
            return MHA_slave_helper.CODE_ERR_READ_ONLY

        # We have come here meaning that the slave is healthy
        return MHA_slave_helper.CODE_SUCCESS

    def get_return_code_string(self, code):
        if code == MHA_slave_helper.CODE_SUCCESS:
            return "[%s] Slave is in SYNC" % self._slave_hostname

        if code == MHA_slave_helper.CODE_ERR_MYSQL_CONN:
            return "[%s] Error connecting to MySQL on the slave" % self._slave_hostname

        if code == MHA_slave_helper.CODE_ERR_READ_ONLY:
            return "[%s] READ_ONLY flag is not set on the slave" % self._slave_hostname

        if code == MHA_slave_helper.CODE_ERR_SLAVE_RUNNING:
            return "[%s] IO and/or SQL threads are not running on the slave" % self._slave_hostname

        if code == MHA_slave_helper.CODE_ERR_SLAVE_LAG:
            return "[%s] Slave lag is more than the allowed threshold" % self._slave_hostname

        return "[%s] Unknown error code" % self._slave_hostname
Пример #12
0
class MHA_slave_helper(object):
    CODE_SUCCESS = 0
    CODE_ERR_MYSQL_CONN = 1
    CODE_ERR_READ_ONLY = 10
    CODE_ERR_SLAVE_RUNNING = 20
    CODE_ERR_SLAVE_LAG = 30

    def __init__(self, slave_host):
        self._slave_host_config_helper = MHA_config_helper(host=slave_host)

        self._slave_hostname = slave_host

        mysql_user = self._slave_host_config_helper.get_mysql_user()
        mysql_password = self._slave_host_config_helper.get_mysql_password()
        host_ip = self._slave_host_config_helper.get_host_ip()

        self._slave_host = MySQL_helper(host=host_ip, user=mysql_user,
                            password=mysql_password) 

    def is_healthy(self):
        # Try to connect to the slave
        if self._slave_host.connect() == False:
            return MHA_slave_helper.CODE_ERR_MYSQL_CONN

        slave_status = self._slave_host.get_slave_status()
        # If we get an empty slave status that means that this is a master
        # If we get a FALSE result that means there was an error running
        # the query
        if slave_status == False or slave_status is None:
            return MHA_slave_helper.CODE_ERR_SLAVE_RUNNING

        # Check if slave threads are running
        if (slave_status['Slave_IO_Running'] != 'Yes' or
            slave_status['Slave_SQL_Running'] != 'Yes'):
            return MHA_slave_helper.CODE_ERR_SLAVE_RUNNING

        # Check if slave lag is within the allowable threshold
        slave_lag_threshold = self._slave_host_config_helper.get_slave_lag_threshold()
        current_slave_lag = slave_status['Seconds_Behind_Master']
        if (current_slave_lag is None or
            int(current_slave_lag) > slave_lag_threshold):
            return MHA_slave_helper.CODE_ERR_SLAVE_LAG

        # Check if read_only flag is set
        if self._slave_host.is_read_only() == False:
            return MHA_slave_helper.CODE_ERR_READ_ONLY

        # We have come here meaning that the slave is healthy
        return MHA_slave_helper.CODE_SUCCESS

    def get_return_code_string(self, code):
        if code == MHA_slave_helper.CODE_SUCCESS:
            return "[%s] Slave is in SYNC" % self._slave_hostname

        if code == MHA_slave_helper.CODE_ERR_MYSQL_CONN:
            return "[%s] Error connecting to MySQL on the slave" % self._slave_hostname

        if code == MHA_slave_helper.CODE_ERR_READ_ONLY:
            return "[%s] READ_ONLY flag is not set on the slave" % self._slave_hostname

        if code == MHA_slave_helper.CODE_ERR_SLAVE_RUNNING:
            return "[%s] IO and/or SQL threads are not running on the slave" % self._slave_hostname

        if code == MHA_slave_helper.CODE_ERR_SLAVE_LAG:
            return "[%s] Slave lag is more than the allowed threshold" % self._slave_hostname

        return "[%s] Unknown error code" % self._slave_hostname
Пример #13
0
class MHA_online_change_helper(object):
    CODE_SUCCESS = 0 
    CODE_ERR_GENERAL = 1 
    CODE_ERR_NO_SSH = 10

    def __init__(self, orig_master_host, orig_master_ip, orig_master_ssh_port,
            new_master_host, new_master_ip, new_master_ssh_port, 
            ssh_options, privileged_users):
        self._orig_master_config_helper = MHA_config_helper(host=orig_master_host)
        self._new_master_config_helper = MHA_config_helper(host=new_master_host)

        self._orig_master = MySQL_helper(host=orig_master_ip, 
                                        user=self._orig_master_config_helper.get_mysql_user(), 
                                        password=self._orig_master_config_helper.get_mysql_password())

        self._new_master = MySQL_helper(host=new_master_ip, 
                                        user=self._new_master_config_helper.get_mysql_user(), 
                                        password=self._new_master_config_helper.get_mysql_password())

        self._orig_master_ip = orig_master_ip

        if orig_master_ssh_port is None:
            self._orig_master_ssh_port = 22
        else:
            self._orig_master_ssh_port = orig_master_ssh_port

        self._new_master_ip = new_master_ip

        if new_master_ssh_port is None:
            self._new_master_ssh_port = 22
        else:
            self._new_master_ssh_port = new_master_ssh_port

        self._ssh_options = ssh_options

        self._privileged_users = privileged_users
	self._user_grants_orig_master = []

    def debug_message(self, message):
	current_datetime = datetime.now().strftime("%Y-%m-%-d %H:%M:%S")
	print "[%s] %s" % (current_datetime, message)

    def get_connected_threads(self, master_obj):
    	""" Returns all threads currently connected to MySQL except for the following:
        - The thread corresponding to the connection of this script
        - The thread belonging to the user "system user"
        - The thread doing "Binlog Dump"
        - The thread that has been in sleeping state for more than a second"""

        my_connection_id = master_obj.get_connection_id()
        threads = []

	processlist = master_obj.get_processlist()
	if processlist == False:
	    return False

        for row in processlist:
            connection_id = row['Id']
            user = row['User']
            host = row['Host']
            command = row['Command']
            state = row['State']
            query_time = row['Time']
            info = row['Info']
            if (my_connection_id == connection_id or 
                command == "Binlog Dump" or
                user == "system user" or 
                (command == "Sleep" and query_time >= 1)):
                continue
            threads.append(row)

        return threads

    def revoke_all_user_privileges(self, master_obj):
	users = master_obj.get_all_users()
	
	if users == False or len(users) < 1:
	    return False

	for user in users:
            if (user['User'] in self._privileged_users or 
                user['User'] == master_obj.get_current_user() or 
                user['Repl_slave_priv'] == 'Y' or 
                user['Repl_client_priv'] == 'Y'):
		continue
	    username = "******" % (user['User'], user['Host'])
	    user_grants = master_obj.get_user_grants(username)
	    if master_obj.revoke_all_privileges(username) == False:
		return False
	    self.debug_message("Privileges revoked for user %s:" % username)
	    for grant in user_grants:
	    	self._user_grants_orig_master.append(grant)
	    	self.debug_message("\t%s" % grant)
	
	return True

    def regrant_all_user_privileges(self, master_obj):
        users = master_obj.get_all_users()
        
        if users == False or len(users) < 1:
            return False

        for user in users:
            if (user['User'] in self._privileged_users or 
                user['User'] == master_obj.get_current_user() or 
                user['Repl_slave_priv'] == 'Y' or 
                user['Repl_client_priv'] == 'Y'):
                continue
            username = "******" % (user['User'], user['Host'])
            self.debug_message("Privileges regranted for user %s:" % username)
            grant_errors = 0
            for grant in master_obj.get_user_grants(username):
                self.debug_message("\t%s" % grant)
                if master_obj.execute_admin_query(grant) == False:
                    self.debug_message("\t\tError please try manually")
                    grant_errors += 1

        if grant_errors > 0:
            return False

        return True

    def execute_stop_command(self):
	# Connect to the new master
	if self._new_master.connect() == False:
	    return MHA_online_change_helper.CODE_ERR_GENERAL

	# Set read_only=1 on the new master to avoid any data inconsistency
	self.debug_message("Setting read_only=1 on the new master ...")
	self._new_master.set_read_only()
	if self._new_master.is_read_only() == False:
	    return MHA_online_change_helper.CODE_ERR_GENERAL

	# Disconnect from the new master because we do not want to change anything on it now
	self._new_master.disconnect()

	# Connect to the original master
	if self._orig_master.connect() == False:
	    return MHA_online_change_helper.CODE_ERR_GENERAL

	# we execute everything below in try..finally because we have to 
        # disconnect and enable log_bin at all cost
	try:
            # Setting read_only=1 on the original master
            self._orig_master.set_read_only()
            if self._orig_master.is_read_only() == False:
                return MHA_online_change_helper.CODE_ERR_GENERAL

            # If we have to manage the VIP, then remove the VIP from the original master
            if self._orig_master_config_helper.get_manage_vip() == True:
                self.debug_message("Removing the VIP from the original master")
                is_vip_removed = MHA_VIP_helper.remove_vip(
                        config_helper=self._orig_master_config_helper,
                        host_ip=self._orig_master_ip,
                        ssh_user=None,
                        ssh_port=self._orig_master_ssh_port,
                        ssh_options=self._ssh_options)

                if is_vip_removed == False:
                    return MHA_online_change_helper.CODE_ERR_GENERAL

	    # Wait upto 5 seconds for all connected threads to disconnect
            self.debug_message("Waiting 5s for all connected threads to disconnect")
	    slept_seconds = 0
	    while slept_seconds < 5:
	        threads = self.get_connected_threads(self._orig_master)
	        if len(threads) > 0:
		    time.sleep(1)
                    slept_seconds += 1
	        else:
		    break

	    # Terminate all threads
	    self.debug_message("Terminating all application threads ...")
	    threads = self.get_connected_threads(self._orig_master)
	    if threads == False:
	        return MHA_online_change_helper.CODE_ERR_GENERAL

	    for thread in threads:
	        self.debug_message("\tTerminating thread Id => %s, User => %s, Host => %s" % 
                                    (thread['Id'], thread['User'], thread['Host']))
	        self._orig_master.kill_connection(connection_id=thread['Id'])
	finally:
	    # Disconnect from the original master and restore binlogging
	    self._orig_master.disconnect()

	return MHA_online_change_helper.CODE_SUCCESS

    def rollback_stop_command(self):
	# Connect to the original master
        if self._orig_master.connect() == False:
            return MHA_online_change_helper.CODE_ERR_GENERAL
	
	rollback_error = 0

	# remove the read_only flag from the orignal master
	self.debug_message("Removing the read_only flag from original master")
	if self._orig_master.unset_read_only() == False:
	    self.debug_message("\tError, please try manually")
	    rollback_error += 1

        # If we have to manage the VIP, then add the VIP back on the original master
        if self._orig_master_config_helper.get_manage_vip() == True:
            self.debug_message("Assigning back the VIP to the original master")
            is_vip_assigned = MHA_VIP_helper.assign_vip(
                    config_helper=self._orig_master_config_helper,
                    host_ip=self._orig_master_ip,
                    ssh_user=None,
                    ssh_port=self._orig_master_ssh_port,
                    ssh_options=self._ssh_options)

            if is_vip_assigned == False:
                rollback_error += 1

	if rollback_error > 0:
	    self.debug_message("Rollback FAILED, there were %s errors" % rollback_error)
	else:
	    self.debug_message("Rollback completed OK")

	# Disconnect from the original master and restore binlogging
	self._orig_master.disconnect()

	return MHA_online_change_helper.CODE_ERR_GENERAL

    def execute_start_command(self):
        # Connect to the new master
        if self._new_master.connect() == False:
            return MHA_online_change_helper.CODE_ERR_GENERAL

        return_val = MHA_online_change_helper.CODE_SUCCESS

        # Remove the read_only flag
        self.debug_message("Removing the read_only flag from the new master")
        self._new_master.unset_read_only()

        # If we have to manage the VIP, then assign the VIP on the new master
        if self._new_master_config_helper.get_manage_vip() == True:
            self.debug_message("Assigning the VIP to the new master")
            is_vip_assigned = MHA_VIP_helper.assign_vip(
                    config_helper=self._new_master_config_helper,
                    host_ip=self._new_master_ip,
                    ssh_user=None,
                    ssh_port=self._new_master_ssh_port,
                    ssh_options=self._ssh_options)

            if is_vip_assigned == False:
                return_val = MHA_online_change_helper.CODE_ERR_GENERAL

        # Disconnect from the new master
        self._new_master.disconnect()

        return return_val
class MHA_online_change_helper(object):
    CODE_SUCCESS = 0
    CODE_ERR_GENERAL = 1
    CODE_ERR_NO_SSH = 10

    def __init__(self, orig_master_host, orig_master_ip, orig_master_ssh_port,
                 new_master_host, new_master_ip, new_master_ssh_port,
                 ssh_options, privileged_users):
        self._orig_master_config_helper = MHA_config_helper(
            host=orig_master_host)
        self._new_master_config_helper = MHA_config_helper(
            host=new_master_host)

        self._orig_master = MySQL_helper(
            host=orig_master_ip,
            user=self._orig_master_config_helper.get_mysql_user(),
            password=self._orig_master_config_helper.get_mysql_password())

        self._new_master = MySQL_helper(
            host=new_master_ip,
            user=self._new_master_config_helper.get_mysql_user(),
            password=self._new_master_config_helper.get_mysql_password())

        self._orig_master_ip = orig_master_ip

        if orig_master_ssh_port is None:
            self._orig_master_ssh_port = 22
        else:
            self._orig_master_ssh_port = orig_master_ssh_port

        self._new_master_ip = new_master_ip

        if new_master_ssh_port is None:
            self._new_master_ssh_port = 22
        else:
            self._new_master_ssh_port = new_master_ssh_port

        self._ssh_options = ssh_options

        self._privileged_users = privileged_users
        self._user_grants_orig_master = []

    def debug_message(self, message):
        current_datetime = datetime.now().strftime("%Y-%m-%-d %H:%M:%S")
        print "[%s] %s" % (current_datetime, message)

    def get_connected_threads(self, master_obj):
        """ Returns all threads currently connected to MySQL except for the following:
        - The thread corresponding to the connection of this script
        - The thread belonging to the user "system user"
        - The thread doing "Binlog Dump"
        - The thread that has been in sleeping state for more than a second"""

        my_connection_id = master_obj.get_connection_id()
        threads = []

        processlist = master_obj.get_processlist()
        if processlist == False:
            return False

        for row in processlist:
            connection_id = row['Id']
            user = row['User']
            host = row['Host']
            command = row['Command']
            state = row['State']
            query_time = row['Time']
            info = row['Info']
            if (my_connection_id == connection_id or command == "Binlog Dump"
                    or user == "system user"
                    or (command == "Sleep" and query_time >= 1)):
                continue
            threads.append(row)

        return threads

    def revoke_all_user_privileges(self, master_obj):
        users = master_obj.get_all_users()

        if users == False or len(users) < 1:
            return False

        for user in users:
            if (user['User'] in self._privileged_users
                    or user['User'] == master_obj.get_current_user()
                    or user['Repl_slave_priv'] == 'Y'
                    or user['Repl_client_priv'] == 'Y'):
                continue
            username = "******" % (user['User'], user['Host'])
            user_grants = master_obj.get_user_grants(username)
            if master_obj.revoke_all_privileges(username) == False:
                return False
            self.debug_message("Privileges revoked for user %s:" % username)
            for grant in user_grants:
                self._user_grants_orig_master.append(grant)
                self.debug_message("\t%s" % grant)

        return True

    def regrant_all_user_privileges(self, master_obj):
        users = master_obj.get_all_users()

        if users == False or len(users) < 1:
            return False

        for user in users:
            if (user['User'] in self._privileged_users
                    or user['User'] == master_obj.get_current_user()
                    or user['Repl_slave_priv'] == 'Y'
                    or user['Repl_client_priv'] == 'Y'):
                continue
            username = "******" % (user['User'], user['Host'])
            self.debug_message("Privileges regranted for user %s:" % username)
            grant_errors = 0
            for grant in master_obj.get_user_grants(username):
                self.debug_message("\t%s" % grant)
                if master_obj.execute_admin_query(grant) == False:
                    self.debug_message("\t\tError please try manually")
                    grant_errors += 1

        if grant_errors > 0:
            return False

        return True

    def execute_stop_command(self):
        # Connect to the new master
        if self._new_master.connect() == False:
            return MHA_online_change_helper.CODE_ERR_GENERAL

        # Set read_only=1 on the new master to avoid any data inconsistency
        self.debug_message("Setting read_only=1 on the new master ...")
        self._new_master.set_read_only()
        if self._new_master.is_read_only() == False:
            return MHA_online_change_helper.CODE_ERR_GENERAL

        # Disconnect from the new master because we do not want to change anything on it now
        self._new_master.disconnect()

        # Connect to the original master
        if self._orig_master.connect() == False:
            return MHA_online_change_helper.CODE_ERR_GENERAL

        # we execute everything below in try..finally because we have to
        # disconnect and enable log_bin at all cost
        try:
            # Setting read_only=1 on the original master
            self._orig_master.set_read_only()
            if self._orig_master.is_read_only() == False:
                return MHA_online_change_helper.CODE_ERR_GENERAL

            # If we have to manage the VIP, then remove the VIP from the original master
            if self._orig_master_config_helper.get_manage_vip() == True:
                self.debug_message("Removing the VIP from the original master")
                is_vip_removed = MHA_VIP_helper.remove_vip(
                    config_helper=self._orig_master_config_helper,
                    host_ip=self._orig_master_ip,
                    ssh_user=None,
                    ssh_port=self._orig_master_ssh_port,
                    ssh_options=self._ssh_options)

                if is_vip_removed == False:
                    return MHA_online_change_helper.CODE_ERR_GENERAL

        # Wait upto 5 seconds for all connected threads to disconnect
            self.debug_message(
                "Waiting 5s for all connected threads to disconnect")
            slept_seconds = 0
            while slept_seconds < 5:
                threads = self.get_connected_threads(self._orig_master)
                if len(threads) > 0:
                    time.sleep(1)
                    slept_seconds += 1
                else:
                    break

        # Terminate all threads
            self.debug_message("Terminating all application threads ...")
            threads = self.get_connected_threads(self._orig_master)
            if threads == False:
                return MHA_online_change_helper.CODE_ERR_GENERAL

            for thread in threads:
                self.debug_message(
                    "\tTerminating thread Id => %s, User => %s, Host => %s" %
                    (thread['Id'], thread['User'], thread['Host']))
                self._orig_master.kill_connection(connection_id=thread['Id'])
        finally:
            # Disconnect from the original master and restore binlogging
            self._orig_master.disconnect()

        return MHA_online_change_helper.CODE_SUCCESS

    def rollback_stop_command(self):
        # Connect to the original master
        if self._orig_master.connect() == False:
            return MHA_online_change_helper.CODE_ERR_GENERAL

        rollback_error = 0

        # remove the read_only flag from the orignal master
        self.debug_message("Removing the read_only flag from original master")
        if self._orig_master.unset_read_only() == False:
            self.debug_message("\tError, please try manually")
            rollback_error += 1

        # If we have to manage the VIP, then add the VIP back on the original master
        if self._orig_master_config_helper.get_manage_vip() == True:
            self.debug_message("Assigning back the VIP to the original master")
            is_vip_assigned = MHA_VIP_helper.assign_vip(
                config_helper=self._orig_master_config_helper,
                host_ip=self._orig_master_ip,
                ssh_user=None,
                ssh_port=self._orig_master_ssh_port,
                ssh_options=self._ssh_options)

            if is_vip_assigned == False:
                rollback_error += 1

        if rollback_error > 0:
            self.debug_message("Rollback FAILED, there were %s errors" %
                               rollback_error)
        else:
            self.debug_message("Rollback completed OK")

# Disconnect from the original master and restore binlogging
        self._orig_master.disconnect()

        return MHA_online_change_helper.CODE_ERR_GENERAL

    def execute_start_command(self):
        # Connect to the new master
        if self._new_master.connect() == False:
            return MHA_online_change_helper.CODE_ERR_GENERAL

        return_val = MHA_online_change_helper.CODE_SUCCESS

        # Remove the read_only flag
        self.debug_message("Removing the read_only flag from the new master")
        self._new_master.unset_read_only()

        # If we have to manage the VIP, then assign the VIP on the new master
        if self._new_master_config_helper.get_manage_vip() == True:
            self.debug_message("Assigning the VIP to the new master")
            is_vip_assigned = MHA_VIP_helper.assign_vip(
                config_helper=self._new_master_config_helper,
                host_ip=self._new_master_ip,
                ssh_user=None,
                ssh_port=self._new_master_ssh_port,
                ssh_options=self._ssh_options)

            if is_vip_assigned == False:
                return_val = MHA_online_change_helper.CODE_ERR_GENERAL

        # Disconnect from the new master
        self._new_master.disconnect()

        return return_val