def show_server_info(servers, options): """Show server information for a list of servers This method will gather information about a running server. If the show_defaults option is specified, the method will also read the configuration file and return a list of the server default settings. If the format option is set, the output will be in the format specified. If the no_headers option is set, the output will not have a header row (no column names) except for format = vertical. If the basedir and start options are set, the method will attempt to start the server in read only mode to get the information. Specifying only basedir will not start the server. The extra start option is designed to make sure the user wants to start the offline server. The user may not wish to do this if there are certain error conditions and/or logs in place that may be overwritten. servers[in] list of server connections in the form <user>:<password>@<host>:<port>:<socket> options[in] dictionary of options (no_headers, format, basedir, start, show_defaults) Returns tuple ((server information), defaults) """ no_headers = options.get("no_headers", False) fmt = options.get("format", "grid") show_defaults = options.get("show_defaults", False) basedir = options.get("basedir", None) datadir = options.get("datadir", None) start = options.get("start", False) show_servers = options.get("show_servers", 0) if show_servers: if os.name == 'nt': ports = options.get("ports", "3306:3333") start_p, end_p = ports.split(":") _show_running_servers(start_p, end_p) else: _show_running_servers() row_dict_lst = [] warnings = [] server_val = {} for server in servers: new_server = None try: test_connect(server, True) except UtilError as util_error: conn_dict = get_connection_dictionary(server) server1 = Server(options={'conn_info': conn_dict}) server_is_off = False # If we got errno 2002 it means can not connect through the # given socket, but if path to socket not empty, server could be # turned off. if util_error.errno == CR_CONNECTION_ERROR: socket = conn_dict.get("unix_socket", "") if socket: mydir = os.path.split(socket)[0] if os.path.isdir(mydir) and len(os.listdir(mydir)) != 0: server_is_off = True # If we got errno 2003 and this is a windows, we do not have # socket, instead we check if server is localhost. elif (util_error.errno == CR_CONN_HOST_ERROR and os.name == 'nt' and server1.is_alias("localhost")): server_is_off = True # If we got errno 1045 it means Access denied, # notify the user if a password was used or not. elif util_error.errno == ER_ACCESS_DENIED_ERROR: use_pass = '******' if conn_dict['passwd'] else 'NO' er = ("Access denied for user '{0}'@'{1}' using password: {2}" ).format(conn_dict['user'], conn_dict['host'], use_pass) # Use the error message from the connection attempt. else: er = [util_error.errmsg] # To propose to start a cloned server for extract the info, # can not predict if the server is really off, but we can do it # in case of socket error, or if one of the related # parameter was given. if (server_is_off or basedir or datadir or start): er = ["Server is offline. To connect, " "you must also provide "] opts = ["basedir", "datadir", "start"] for opt in tuple(opts): try: if locals()[opt] is not None: opts.remove(opt) except KeyError: pass if opts: er.append(", ".join(opts[0:-1])) if len(opts) > 1: er.append(" and the ") er.append(opts[-1]) er.append(" option") raise UtilError("".join(er)) if not start: raise UtilError("".join(er)) else: try: server_val = parse_connection(server, None, options) except: raise UtilError("Source connection values invalid" " or cannot be parsed.") new_server = _start_server(server_val, basedir, datadir, options) info_dict, defaults = _server_info(server, show_defaults, options) warnings.extend(info_dict['warnings']) if info_dict: row_dict_lst.append(info_dict) if new_server: # Need to stop the server! new_server.disconnect() _stop_server(server_val, basedir, options) # Get the row values stored in the dictionaries rows = [[row_dict[key] for key in _COLUMNS] for row_dict in row_dict_lst] print_list(sys.stdout, fmt, _COLUMNS, rows, no_headers) if warnings: print("\n# List of Warnings: \n") for warning in warnings: print("WARNING: {0}\n".format(warning)) # Print the default configurations. if show_defaults and len(defaults) > 0: for row in defaults: print(" {0}".format(row))
def move_binlogs_from_server(server_cnx_val, destination, options, bin_basename=None, bin_index=None, relay_basename=None): """Relocate binary logs from the given server to a new location. This function relocate the binary logs from a MySQL server to the specified destination directory, attending to the specified options. server_cnx_val[in] Dictionary with the connection values for the server. destination[in] Path of the destination directory for the binary log files. options[in] Dictionary of options (log_type, skip_flush_binlogs, modified_before, sequence, verbosity). bin_basename[in] Base name for the binlog files, i.e., same as the value for the server option --log-bin. It replaces the server variable 'log_bin_basename' for versions < 5.6.2, otherwise it is ignored. bin_index[in] Path of the binlog index file. It replaces the server variable 'log_bin_index' for versions < 5.6.4, otherwise it is ignored. relay_basename[in] Base name for the relay log files, i.e., filename without the extension (sequence number). Same as the value for the server option --relay-log. It replaces the server variable 'relay_log_basename' for versions < 5.6.2, otherwise it is ignored. """ log_type = options.get('log_type', LOG_TYPE_BIN) skip_flush = options['skip_flush_binlogs'] verbosity = options['verbosity'] # Connect to server server_options = { 'conn_info': server_cnx_val, } srv = Server(server_options) srv.connect() # Check if the server is running locally (not remote server). if not srv.is_alias('localhost'): raise UtilError("You are using a remote server. This utility must be " "run on the local server. It does not support remote " "access to the binary log files.") # Check privileges. _check_privileges(srv, options) # Process binlog files. if log_type in (LOG_TYPE_BIN, LOG_TYPE_ALL): # Get log_bin_basename (available since MySQL 5.6.2). if srv.check_version_compat(5, 6, 2): if bin_basename: print( _WARN_MSG_VAL_NOT_REQ_FOR_SERVER.format( value='bin basename', min_version='5.6.2', var_name='log_bin_basename')) binlog_basename = srv.select_variable('log_bin_basename') if verbosity > 0: print("#") print("# log_bin_basename: {0}".format(binlog_basename)) binlog_source, binlog_file = os.path.split(binlog_basename) # Get log_bin_index (available since MySQL 5.6.4). if srv.check_version_compat(5, 6, 4): if bin_index: print( _WARN_MSG_VAL_NOT_REQ_FOR_SERVER.format( value='bin index', min_version='5.6.4', var_name='log_bin_index')) binlog_index = srv.select_variable('log_bin_index') else: binlog_index = None action = _ACTION_SEARCH_INDEX.format(file_type='bin-log') print( _WARN_MSG_VAR_NOT_AVAILABLE.format( var_name='log_bin_basename', host=srv.host, port=srv.port, min_version='5.6.4', action=action)) if verbosity > 0: print("# log_bin_index: {0}".format(binlog_index)) else: if bin_basename: binlog_source, binlog_file = os.path.split(bin_basename) else: action = _ACTION_DATADIR_USED.format(file_type='bin-log') print( _WARN_MSG_VAR_NOT_AVAILABLE.format( var_name='log_bin_basename', host=srv.host, port=srv.port, min_version='5.6.2', action=action)) # Get datadir value. binlog_source = srv.select_variable('datadir') binlog_file = None if verbosity > 0: print("#") print("# datadir: {0}".format(binlog_source)) binlog_index = bin_index # Move binlog files. num_files = _move_binlogs(binlog_source, destination, LOG_TYPE_BIN, options, basename=binlog_file, index_file=binlog_index, skip_latest=True) print("#") # Flush binary logs to reload server's cache after move. if not skip_flush and num_files > 0: # Note: log_type for FLUSH available since MySQL 5.5.3. if srv.check_version_compat(5, 5, 3): print(_INFO_MSG_FLUSH_LOGS.format(log_type='binary')) srv.flush_logs(log_type='BINARY') else: print( _WARN_MSG_FLUSH_LOG_TYPE.format(log_type='binary', host=srv.host, port=srv.port)) print("#") if log_type in (LOG_TYPE_RELAY, LOG_TYPE_ALL): # Get relay_log_basename (available since MySQL 5.6.2). if srv.check_version_compat(5, 6, 2): if relay_basename: print( _WARN_MSG_VAL_NOT_REQ_FOR_SERVER.format( value='relay basename', min_version='5.6.2', var_name='relay_log_basename')) relay_log_basename = srv.select_variable('relay_log_basename') if verbosity > 0: print("#") print("# relay_log_basename: {0}".format(relay_log_basename)) relay_source, relay_file = os.path.split(relay_log_basename) else: if relay_basename: relay_source, relay_file = os.path.split(relay_basename) else: action = _ACTION_DATADIR_USED.format(file_type='relay-log') print( _WARN_MSG_VAR_NOT_AVAILABLE.format( var_name='relay_log_basename', host=srv.host, port=srv.port, min_version='5.6.2', action=action)) # Get datadir value. relay_source = srv.select_variable('datadir') relay_file = None if verbosity > 0: print("#") print("# datadir: {0}".format(relay_source)) # Get relay_log_index (available for all supported versions). relay_log_index = srv.select_variable('relay_log_index') if verbosity > 0: print("# relay_log_index: {0}".format(relay_log_index)) # Move relay log files. num_files = _move_binlogs(relay_source, destination, LOG_TYPE_RELAY, options, basename=relay_file, index_file=relay_log_index, skip_latest=True) print("#") # Flush relay logs to reload server's cache after move. if not skip_flush and num_files > 0: # Note: log_type for FLUSH available since MySQL 5.5.3. if srv.check_version_compat(5, 5, 3): print(_INFO_MSG_FLUSH_LOGS.format(log_type='relay')) srv.flush_logs(log_type='RELAY') else: print( _WARN_MSG_FLUSH_LOG_TYPE.format(log_type='relay', host=srv.host, port=srv.port)) print("#") print("#...done.\n#")
def show_server_info(servers, options): """Show server information for a list of servers This method will gather information about a running server. If the show_defaults option is specified, the method will also read the configuration file and return a list of the server default settings. If the format option is set, the output will be in the format specified. If the no_headers option is set, the output will not have a header row (no column names) except for format = vertical. If the basedir and start options are set, the method will attempt to start the server in read only mode to get the information. Specifying only basedir will not start the server. The extra start option is designed to make sure the user wants to start the offline server. The user may not wish to do this if there are certain error conditions and/or logs in place that may be overwritten. servers[in] list of server connections in the form <user>:<password>@<host>:<port>:<socket> options[in] dictionary of options (no_headers, format, basedir, start, show_defaults) Returns tuple ((server information), defaults) """ no_headers = options.get("no_headers", False) fmt = options.get("format", "grid") show_defaults = options.get("show_defaults", False) basedir = options.get("basedir", None) datadir = options.get("datadir", None) start = options.get("start", False) show_servers = options.get("show_servers", 0) if show_servers: if os.name == 'nt': ports = options.get("ports", "3306:3333") start_p, end_p = ports.split(":") _show_running_servers(start_p, end_p) else: _show_running_servers() ssl_dict = {} ssl_dict['ssl_cert'] = options.get("ssl_cert", None) ssl_dict['ssl_ca'] = options.get("ssl_ca", None) ssl_dict['ssl_key'] = options.get("ssl_key", None) ssl_dict['ssl'] = options.get("ssl", None) row_dict_lst = [] warnings = [] server_val = {} for server in servers: new_server = None try: test_connect(server, throw_errors=True, ssl_dict=ssl_dict) except UtilError as util_error: conn_dict = get_connection_dictionary(server, ssl_dict=ssl_dict) server1 = Server(options={'conn_info': conn_dict}) server_is_off = False # If we got errno 2002 it means can not connect through the # given socket. if util_error.errno == CR_CONNECTION_ERROR: socket = conn_dict.get("unix_socket", "") if socket: msg = ("Unable to connect to server using socket " "'{0}'.".format(socket)) if os.path.isfile(socket): err_msg = ["{0} Socket file is not valid.".format(msg)] else: err_msg = [ "{0} Socket file does not " "exist.".format(msg) ] # If we got errno 2003 and we do not have # socket, instead we check if server is localhost. elif (util_error.errno == CR_CONN_HOST_ERROR and server1.is_alias("localhost")): server_is_off = True # If we got errno 1045 it means Access denied, # notify the user if a password was used or not. elif util_error.errno == ER_ACCESS_DENIED_ERROR: use_pass = '******' if conn_dict['passwd'] else 'NO' err_msg = ("Access denied for user '{0}'@'{1}' using " "password: {2}".format(conn_dict['user'], conn_dict['host'], use_pass)) # Use the error message from the connection attempt. else: err_msg = [util_error.errmsg] # To propose to start a cloned server for extract the info, # can not predict if the server is really off, but we can do it # in case of socket error, or if one of the related # parameter was given. if server_is_off or basedir or datadir or start: err_msg = [ "Server is offline. To connect, " "you must also provide " ] opts = ["basedir", "datadir", "start"] for opt in tuple(opts): try: if locals()[opt] is not None: opts.remove(opt) except KeyError: pass if opts: err_msg.append(", ".join(opts[0:-1])) if len(opts) > 1: err_msg.append(" and the ") err_msg.append(opts[-1]) err_msg.append(" option") raise UtilError("".join(err_msg)) if not start: raise UtilError("".join(err_msg)) else: try: server_val = parse_connection(server, None, options) except: raise UtilError("Source connection values invalid" " or cannot be parsed.") new_server = _start_server(server_val, basedir, datadir, options) info_dict, defaults = _server_info(server, show_defaults, options) warnings.extend(info_dict['warnings']) if info_dict: row_dict_lst.append(info_dict) if new_server: # Need to stop the server! new_server.disconnect() _stop_server(server_val, basedir, options) # Get the row values stored in the dictionaries rows = [[row_dict[key] for key in _COLUMNS] for row_dict in row_dict_lst] print_list(sys.stdout, fmt, _COLUMNS, rows, no_headers) if warnings: print("\n# List of Warnings: \n") for warning in warnings: print("WARNING: {0}\n".format(warning)) # Print the default configurations. if show_defaults and len(defaults) > 0: for row in defaults: print(" {0}".format(row))
def move_binlogs_from_server(server_cnx_val, destination, options, bin_basename=None, bin_index=None, relay_basename=None): """Relocate binary logs from the given server to a new location. This function relocate the binary logs from a MySQL server to the specified destination directory, attending to the specified options. server_cnx_val[in] Dictionary with the connection values for the server. destination[in] Path of the destination directory for the binary log files. options[in] Dictionary of options (log_type, skip_flush_binlogs, modified_before, sequence, verbosity). bin_basename[in] Base name for the binlog files, i.e., same as the value for the server option --log-bin. It replaces the server variable 'log_bin_basename' for versions < 5.6.2, otherwise it is ignored. bin_index[in] Path of the binlog index file. It replaces the server variable 'log_bin_index' for versions < 5.6.4, otherwise it is ignored. relay_basename[in] Base name for the relay log files, i.e., filename without the extension (sequence number). Same as the value for the server option --relay-log. It replaces the server variable 'relay_log_basename' for versions < 5.6.2, otherwise it is ignored. """ log_type = options.get('log_type', LOG_TYPE_BIN) skip_flush = options['skip_flush_binlogs'] verbosity = options['verbosity'] # Connect to server server_options = { 'conn_info': server_cnx_val, } srv = Server(server_options) srv.connect() # Check if the server is running locally (not remote server). if not srv.is_alias('localhost'): raise UtilError("You are using a remote server. This utility must be " "run on the local server. It does not support remote " "access to the binary log files.") # Check privileges. _check_privileges_to_move_binlogs(srv, options) # Process binlog files. if log_type in (LOG_TYPE_BIN, LOG_TYPE_ALL): # Get log_bin_basename (available since MySQL 5.6.2). if srv.check_version_compat(5, 6, 2): if bin_basename: print(_WARN_MSG_VAL_NOT_REQ_FOR_SERVER.format( value='bin basename', min_version='5.6.2', var_name='log_bin_basename')) binlog_basename = srv.select_variable('log_bin_basename') if verbosity > 0: print("#") print("# log_bin_basename: {0}".format(binlog_basename)) binlog_source, binlog_file = os.path.split(binlog_basename) # Get log_bin_index (available since MySQL 5.6.4). if srv.check_version_compat(5, 6, 4): if bin_index: print(_WARN_MSG_VAL_NOT_REQ_FOR_SERVER.format( value='bin index', min_version='5.6.4', var_name='log_bin_index')) binlog_index = srv.select_variable('log_bin_index') else: binlog_index = None action = _ACTION_SEARCH_INDEX.format(file_type='bin-log') print(_WARN_MSG_VAR_NOT_AVAILABLE.format( var_name='log_bin_basename', host=srv.host, port=srv.port, min_version='5.6.4', action=action)) if verbosity > 0: print("# log_bin_index: {0}".format(binlog_index)) else: if bin_basename: binlog_source, binlog_file = os.path.split(bin_basename) else: action = _ACTION_DATADIR_USED.format(file_type='bin-log') print(_WARN_MSG_VAR_NOT_AVAILABLE.format( var_name='log_bin_basename', host=srv.host, port=srv.port, min_version='5.6.2', action=action)) # Get datadir value. binlog_source = srv.select_variable('datadir') binlog_file = None if verbosity > 0: print("#") print("# datadir: {0}".format(binlog_source)) binlog_index = bin_index # Move binlog files. num_files = _move_binlogs( binlog_source, destination, LOG_TYPE_BIN, options, basename=binlog_file, index_file=binlog_index, skip_latest=True) print("#") # Flush binary logs to reload server's cache after move. if not skip_flush and num_files > 0: # Note: log_type for FLUSH available since MySQL 5.5.3. if srv.check_version_compat(5, 5, 3): print(_INFO_MSG_FLUSH_LOGS.format(log_type='binary')) srv.flush_logs(log_type='BINARY') else: print(_WARN_MSG_FLUSH_LOG_TYPE.format(log_type='binary', host=srv.host, port=srv.port)) print("#") if log_type in (LOG_TYPE_RELAY, LOG_TYPE_ALL): # Get relay_log_basename (available since MySQL 5.6.2). if srv.check_version_compat(5, 6, 2): if relay_basename: print(_WARN_MSG_VAL_NOT_REQ_FOR_SERVER.format( value='relay basename', min_version='5.6.2', var_name='relay_log_basename')) relay_log_basename = srv.select_variable('relay_log_basename') if verbosity > 0: print("#") print("# relay_log_basename: {0}".format(relay_log_basename)) relay_source, relay_file = os.path.split(relay_log_basename) else: if relay_basename: relay_source, relay_file = os.path.split(relay_basename) else: action = _ACTION_DATADIR_USED.format(file_type='relay-log') print(_WARN_MSG_VAR_NOT_AVAILABLE.format( var_name='relay_log_basename', host=srv.host, port=srv.port, min_version='5.6.2', action=action)) # Get datadir value. relay_source = srv.select_variable('datadir') relay_file = None if verbosity > 0: print("#") print("# datadir: {0}".format(relay_source)) # Get relay_log_index (available for all supported versions). relay_log_index = srv.select_variable('relay_log_index') if verbosity > 0: print("# relay_log_index: {0}".format(relay_log_index)) # Move relay log files. num_files = _move_binlogs( relay_source, destination, LOG_TYPE_RELAY, options, basename=relay_file, index_file=relay_log_index, skip_latest=True) print("#") # Flush relay logs to reload server's cache after move. if not skip_flush and num_files > 0: # Note: log_type for FLUSH available since MySQL 5.5.3. if srv.check_version_compat(5, 5, 3): print(_INFO_MSG_FLUSH_LOGS.format(log_type='relay')) srv.flush_logs(log_type='RELAY') else: print(_WARN_MSG_FLUSH_LOG_TYPE.format(log_type='relay', host=srv.host, port=srv.port)) print("#") print("#...done.\n#")
if opt.basedir and opt.basedir[0] == '~': options['basedir'] = os.path.expanduser(opt.basedir) if opt.new_data and opt.new_data[0] == '.': options['new_data'] = os.path.abspath(opt.new_data) if opt.basedir and opt.basedir[0] == '.': options['basedir'] = os.path.abspath(opt.basedir) # Parse source connection values if we have a running server if opt.basedir is None: conn_options = get_ssl_dict(opt) try: conn = parse_connection(opt.server, options=conn_options) # Now check for local server server = Server({'conn_info': conn}) if not server.is_alias('localhost'): parser.error("Server to be cloned must be running on the same " "machine as mysqlserverclone.") except exception.FormatError: _, err, _ = sys.exc_info() parser.error("Server connection values invalid: %s." % err) except exception.UtilError: _, err, _ = sys.exc_info() parser.error("Server connection values invalid: %s." % err.errmsg) else: conn = None try: serverclone.clone_server(conn, options) except exception.UtilError: _, e, _ = sys.exc_info()