コード例 #1
0
ファイル: exceptions.py プロジェクト: blylei/frabit
 def __str__(self):
     # Returns the first line
     if self.args and self.args[0]:
         from frabit.utils import force_str
         return force_str(self.args[0]).splitlines()[0].strip()
     else:
         return ''
コード例 #2
0
ファイル: mysql.py プロジェクト: blylei/frabit
 def has_backup_privileges(self):
     """
     Returns true if current user has efficient privileges,include below:
     super :
     processlist:
     replicate client:
     replicate slave :
     """
     privileges_info = """
     SELECT
     concat(Select_priv
           ,Insert_priv
           ,Update_priv
           ,Delete_priv
           ,Create_priv
           ,Drop_priv
           ,Reload_priv
           ,Shutdown_priv
           ,Process_priv
           ,File_priv
           ,Grant_priv
           ,References_priv
           ,Index_priv
           ,Alter_priv
           ,Show_db_priv
           ,Super_priv
           ,Lock_tables_priv
           ,Execute_priv
           ,Repl_slave_priv
           ,Repl_client_priv
           ,Create_view_priv
           ,Show_view_priv
           ,Create_routine_priv
           ,Alter_routine_priv
           ,Create_user_priv
           ,Event_priv
           ,Trigger_priv
           )
     FROM mysql.user
     WHERE user = CURRENT_USER
       AND host = CURRENT_HOST 
     """
     try:
         cur = self._cursor()
         cur.execute(privileges_info)
         return cur.fetchone()[0]
     except (MysqlInterfaceError, MysqlException) as e:
         _logger.debug(
             "Error checking privileges needed for backups: {}".format(
                 force_str(e).strip()))
         return None
コード例 #3
0
ファイル: mysql.py プロジェクト: blylei/frabit
    def connect(self):
        """
        Generic function for MySQL connection (using mysql-connector-python)
        """

        if not self._check_connection():
            try:
                self._conn = mysql.connector.connect(self.conn_parameters)
            # If mysql-connector-python fails to connect to the host, raise the appropriate exception
            except connector.PoolError as e:
                raise MysqlConnectError(force_str(e).strip())
            # Register the connection to the list of live connections
            _live_connections.append(self)
        return self._conn
コード例 #4
0
ファイル: compression.py プロジェクト: blylei/frabit
    def decompress(self, src, dst):
        """
        Decompress using the object defined in the sublcass

        :param src: source file to decompress
        :param dst: destination of the decompression
        """
        try:
            with closing(self._decompressor(src)) as istream:
                with open(dst, 'wb') as ostream:
                    shutil.copyfileobj(istream, ostream)
        except Exception as e:
            # you won't get more information from the compressors anyway
            raise CommandFailedException(
                dict(ret=None, err=force_str(e), out=None))
        return 0
コード例 #5
0
ファイル: mysql.py プロジェクト: blylei/frabit
    def current_size(self):
        """
        Returns the total size of the MySQL server
        """
        if not self.has_backup_privileges:
            return None

        try:
            cur = self._cursor()
            cur.execute("SELECT sum(pg_tablespace_size(oid)) "
                        "FROM pg_tablespace")
            return cur.fetchone()[0]
        except (MysqlInterfaceError, MysqlException) as e:
            _logger.debug("Error retrieving MySQL total size: %s",
                          force_str(e).strip())
            return None
コード例 #6
0
ファイル: cli.py プロジェクト: blylei/frabit
def list_files(args):
    """
    List all the files for a single backup
    """
    server = get_server(args)

    # Retrieves the backup
    backup_info = parse_backup_id(server, args)
    try:
        for line in backup_info.get_list_of_files(args.target):
            output.info(line, log=False)
    except BinlogHasPurged as e:
        output.error(
            "invalid xlog segment name %r\n"
            "HINT: Please run \"barman rebuild-xlogdb %s\" "
            "to solve this issue", force_str(e), server.config.name)
        output.close_and_exit()
コード例 #7
0
ファイル: mysql.py プロジェクト: blylei/frabit
 def server_txt_version(self):
     """
     Human readable version of MySQL (returned by the server)
     """
     try:
         cur = self._cursor()
         cur.execute("SELECT version()")
         info = cur.fetchall()[0][0].split("-")[0]
         version = {
             "major": info.split(".")[0],
             "minor": info.split(".")[1],
             "patch": info.split(".")[2]
         }
         return version
     except (MysqlInterfaceError, MysqlException) as e:
         _logger.debug("Error retrieving MySQL version: {}".format(
             force_str(e).strip()))
         return None
コード例 #8
0
ファイル: mysql.py プロジェクト: blylei/frabit
    def current_binlog_info(self):
        """
        Get detailed information about the current Binlog position in MySQL.

        This method returns a dictionary containing the following data:

         * file_name
         * position
         * gtid

        :rtype: dict
        """
        try:
            cur = self._cursor()
            cur.execute("SHOW MASTER STATUS;")
            return cur.fetchone()
        except (MysqlInterfaceError, MysqlException) as e:
            _logger.debug(
                "Error retrieving current binlog detailed information: {}".
                format(force_str(e).strip()))
        return None
コード例 #9
0
ファイル: exceptions.py プロジェクト: blylei/frabit
    def from_command_error(cls, cmd, e, msg):
        """
        This method build a DataTransferFailure exception and report the
        provided message to the user (both console and log file) along with
        the output of the failed command.

        :param str cmd: The command that failed the transfer
        :param CommandFailedException e: The exception we are handling
        :param str msg: a descriptive message on what we are trying to do
        :return DataTransferFailure: will contain the message provided in msg
        """
        try:
            details = msg
            details += "\n%s error:\n" % cmd
            details += e.args[0]['out']
            details += e.args[0]['err']
            return cls(details)
        except (TypeError, NameError):
            # If it is not a dictionary just convert it to a string
            from frabit.utils import force_str
            return cls(force_str(e.args))
コード例 #10
0
ファイル: mysql.py プロジェクト: blylei/frabit
    def get_status(self, name, is_global=True):
        """
        Get MySQL global or session status

        :rtype: str
        """
        cur = self._cursor()
        if is_global:
            pass
        try:
            cur.execute(
                "SELECT name, setting FROM pg_settings "
                "WHERE name IN ('config_file', 'hba_file', 'ident_file')")
            for cname, cpath in cur.fetchall():
                self.configuration_files[cname] = cpath
        except (MysqlInterfaceError, MysqlException) as e:
            _logger.debug(
                "Error retrieving MySQL configuration files "
                "location: %s",
                force_str(e).strip())
            self.configuration_files = {}

        return self.configuration_files
コード例 #11
0
ファイル: mysql.py プロジェクト: blylei/frabit
    def get_replication_stats(self):
        """
        Returns replication information dict
        """
        try:
            cur = self._cursor()

            if not self.has_backup_privileges:
                raise BackupInefficientPrivilege()
            '''
            Slave_IO_State:
            Master_Host:
            Master_User:
            Master_Port:
            Connect_Retry:
            Master_Log_File:
            Read_Master_Log_Pos:
            Relay_Log_File:
            Relay_Log_Pos:
            Relay_Master_Log_File:
            Slave_IO_Running:
            Slave_SQL_Running:
            Replicate_Do_DB:
            Replicate_Ignore_DB:
            Replicate_Do_Table:
            Replicate_Ignore_Table:
            Replicate_Wild_Do_Table:
            Replicate_Wild_Ignore_Table:
            Last_Errno:
            Last_Error:
            Skip_Counter:
            Exec_Master_Log_Pos:
            Relay_Log_Space:
            Until_Condition:
            Until_Log_File:
            Until_Log_Pos:
            Master_SSL_Allowed:
            Master_SSL_CA_File:
            Master_SSL_CA_Path:
            Master_SSL_Cert:
            Master_SSL_Cipher:
            Master_SSL_Key:
            Seconds_Behind_Master:
            Master_SSL_Verify_Server_Cert:
            Last_IO_Errno:
            Last_IO_Error:
            Last_SQL_Errno:
            Last_SQL_Error:
            Replicate_Ignore_Server_Ids:
            Master_Server_Id:
            Master_UUID:
            Master_Info_File:
            SQL_Delay:
            SQL_Remaining_Delay:
            Slave_SQL_Running_State:
            Master_Retry_Count:
            Master_Bind:
            Last_IO_Error_Timestamp:
            Last_SQL_Error_Timestamp:
            Master_SSL_Crl:
            Master_SSL_Crlpath:
            Retrieved_Gtid_Set:
            Executed_Gtid_Set:
            Auto_Position:
            Replicate_Rewrite_DB:
            Channel_Name:
            Master_TLS_Version:
            '''
            # Execute the query
            cur.execute("".format())

            # Generate a list of standby objects
            return cur.fetchall()
        except (MysqlInterfaceError, MysqlException) as e:
            _logger.debug(
                "Error retrieving status of replica servers: {}".format(
                    force_str(e).strip()))
            return None
コード例 #12
0
ファイル: cli.py プロジェクト: blylei/frabit
def recover(args):
    """
    Recover a server at a given time, name, LSN or xid
    """
    server = get_server(args)

    # Retrieves the backup
    backup_id = parse_backup_id(server, args)
    if backup_id.status not in BackupInfo.STATUS_COPY_DONE:
        output.error("Cannot recover from backup '{id}' of server '{name}': "
                     "backup status is not DONE".format(
                         id=args.backup_id, name=server.config.name))
        output.close_and_exit()

    # decode the tablespace relocation rules
    tablespaces = {}
    if args.tablespace:
        for rule in args.tablespace:
            try:
                tablespaces.update([rule.split(':', 1)])
            except ValueError:
                output.error(
                    "Invalid tablespace relocation rule '%s'\n"
                    "HINT: The valid syntax for a relocation rule is "
                    "NAME:LOCATION", rule)
                output.close_and_exit()

    # validate the rules against the tablespace list
    valid_tablespaces = []
    if backup_id.tablespaces:
        valid_tablespaces = [
            tablespace_data.name for tablespace_data in backup_id.tablespaces
        ]
    for item in tablespaces:
        if item not in valid_tablespaces:
            output.error(
                "Invalid tablespace name '%s'\n"
                "HINT: Please use any of the following "
                "tablespaces: %s", item, ', '.join(valid_tablespaces))
            output.close_and_exit()

    # explicitly disallow the rsync remote syntax (common mistake)
    if ':' in args.destination_directory:
        output.error(
            "The destination directory parameter "
            "cannot contain the ':' character\n"
            "HINT: If you want to do a remote recovery you have to use "
            "the --remote-ssh-command option")
        output.close_and_exit()
    if args.retry_sleep is not None:
        server.config.basebackup_retry_sleep = args.retry_sleep
    if args.retry_times is not None:
        server.config.basebackup_retry_times = args.retry_times
    if hasattr(args, 'get_wal'):
        if args.get_wal:
            server.config.recovery_options.add(RecoveryOptions.GET_WAL)
        else:
            server.config.recovery_options.remove(RecoveryOptions.GET_WAL)
    if args.jobs is not None:
        server.config.parallel_jobs = args.jobs
    if hasattr(args, 'bwlimit'):
        server.config.bandwidth_limit = args.bwlimit

    target_options = [
        'target_tli', 'target_time', 'target_xid', 'target_lsn', 'target_name',
        'target_immediate'
    ]
    specified_target_options = len(
        [option for option in target_options if getattr(args, option)])
    if specified_target_options > 1:
        output.error(
            "You cannot specify multiple targets for the recovery operation")
        output.close_and_exit()

    if hasattr(args, 'network_compression'):
        if args.network_compression and args.remote_ssh_command is None:
            output.error("Network compression can only be used with "
                         "remote recovery.\n"
                         "HINT: If you want to do a remote recovery "
                         "you have to use the --remote-ssh-command option")
            output.close_and_exit()
        server.config.network_compression = args.network_compression

    with closing(server):
        try:
            server.recover(backup_id,
                           args.destination_directory,
                           tablespaces=tablespaces,
                           target_tli=args.target_tli,
                           target_time=args.target_time,
                           target_xid=args.target_xid,
                           target_lsn=args.target_lsn,
                           target_name=args.target_name,
                           target_immediate=args.target_immediate,
                           exclusive=args.exclusive,
                           remote_command=args.remote_ssh_command,
                           target_action=getattr(args, 'target_action', None),
                           standby_mode=getattr(args, 'standby_mode', None))
        except RecoveryException as exc:
            output.error(force_str(exc))

    output.close_and_exit()