\x89PNG\r\n\x1a\n\x00\x00\x00\x0DIHDR\x00\x00\x00\x01\x00 \x00\x00\x01\x08\x06\x00\x00\x00\x1F\x15\xC4\x89\x00\x00\x00 \x0AIDATx\x9Ccb\x00\x00\x00\x06\x00\x03\x1A\x05\x9D\x00\x00 \x00\x00IEND\xAE\x42\x60\x82 csarite.com
KUJUNTI.ID MINISH3LL
Path : /var/www/html/yedekledb24/DatabaseBackupMasterv7/
(S)h3ll Cr3at0r :
F!le Upl0ad :

B-Con CMD Config cPanel C-Rdp D-Log Info Jump Mass Ransom Symlink vHost Zone-H

Current File : /var/www/html/yedekledb24/DatabaseBackupMasterv7/perform_incremental_mysql_backup.py


import os
import subprocess
import tempfile
import logging
import shutil
import tarfile
from models import BackupLog
from pathlib import Path

logger = logging.getLogger(__name__)

def perform_incremental_mysql_backup(db_conn, temp_file, job, parent_log_id=None):
    """
    Perform incremental MySQL/MariaDB backup using XtraBackup or MariaBackup.
    
    Args:
        db_conn (DatabaseConnection): Database connection object
        temp_file (str): Path to temporary file for backup
        job (BackupJob): Backup job configuration
        parent_log_id (int, optional): ID of parent backup log entry
        
    Returns:
        bool: True if backup successful, False otherwise
    """
    try:
        # Detect database type and select the appropriate backup tool
        db_type = db_conn.db_type.lower()
        
        # Select the appropriate backup tool based on database type
        if db_type == 'mariadb':
            backup_tool = 'mariabackup'
            logger.info("Using MariaBackup for MariaDB")
        elif db_type == 'mysql':
            backup_tool = 'xtrabackup'
            logger.info("Using Percona XtraBackup for MySQL")
        else:
            logger.error(f"Unsupported database type for incremental backup: {db_type}")
            return False
            
        # Check if the selected backup tool is installed
        try:
            subprocess.run([backup_tool, '--version'], capture_output=True, check=True)
        except (subprocess.SubprocessError, FileNotFoundError):
            logger.error(f"{backup_tool} is not installed. Cannot perform incremental backup.")
            return False
            
        # Set MySQL/MariaDB connection parameters
        mysql_args = {
            'host': db_conn.host,
            'port': db_conn.port,
            'user': db_conn.username,
            'password': db_conn.password,
            'database': db_conn.database
        }
        
        # Create a temporary directory for the backup
        backup_dir = tempfile.mkdtemp(prefix=f"backup_{mysql_args['database']}_")
        
        # Determine backup type
        backup_type = job.backup_method  # 'full', 'incremental', 'differential'
        
        # Default command for full backup
        cmd = [
            backup_tool,
            '--backup',
            f'--target-dir={backup_dir}',
            f'--host={mysql_args["host"]}',
            f'--port={mysql_args["port"]}',
            f'--user={mysql_args["user"]}',
            f'--password={mysql_args["password"]}'
        ]
        
        # For incremental/differential backup, find the base backup
        parent_backup_dir = None
        if backup_type in ['incremental', 'differential']:
            if parent_log_id:
                parent_backup = BackupLog.query.get(parent_log_id)
            else:
                # Find the last full backup for this job
                parent_backup = BackupLog.query.filter_by(
                    job_id=job.id,
                    backup_method='full',
                    status='success'
                ).order_by(BackupLog.timestamp.desc()).first()
                
            if not parent_backup:
                logger.error(f"No parent backup found for {backup_type} backup. Performing full backup instead.")
                backup_type = 'full'
            else:
                # Extract the parent backup to a temporary location
                if os.path.exists(parent_backup.backup_file):
                    logger.info(f"Using parent backup from {parent_backup.timestamp}")
                    
                    # Create a temporary directory for the parent backup
                    parent_backup_dir = tempfile.mkdtemp(prefix=f"backup_parent_")
                    
                    # Extract the parent backup
                    if parent_backup.backup_file.endswith('.tar.gz'):
                        with tarfile.open(parent_backup.backup_file, 'r:gz') as tar:
                            tar.extractall(path=parent_backup_dir)
                            # Find the extracted directory in parent_backup_dir
                            subdirs = [d for d in os.listdir(parent_backup_dir) if os.path.isdir(os.path.join(parent_backup_dir, d))]
                            if subdirs:
                                parent_backup_dir = os.path.join(parent_backup_dir, subdirs[0])
                    else:
                        logger.error(f"Unsupported parent backup format: {parent_backup.backup_file}")
                        backup_type = 'full'  # Fall back to full backup
                    
                    # Add incremental backup parameters
                    if backup_type == 'incremental' and parent_backup_dir:
                        cmd.append('--incremental')
                        cmd.append(f'--incremental-basedir={parent_backup_dir}')
                    elif backup_type == 'differential' and parent_backup_dir:
                        cmd.append('--incremental')
                        # Find the original full backup (base) for differential backup
                        if parent_backup.backup_method == 'full':
                            cmd.append(f'--incremental-basedir={parent_backup_dir}')
                        else:
                            # Traverse up the backup chain until we find a full backup
                            base_backup = parent_backup
                            while base_backup and base_backup.backup_method != 'full':
                                base_backup = BackupLog.query.get(base_backup.parent_backup_id)
                                
                            if base_backup and os.path.exists(base_backup.backup_file):
                                # Extract the base backup
                                base_backup_dir = tempfile.mkdtemp(prefix=f"backup_base_")
                                with tarfile.open(base_backup.backup_file, 'r:gz') as tar:
                                    tar.extractall(path=base_backup_dir)
                                    # Find the extracted directory in base_backup_dir
                                    subdirs = [d for d in os.listdir(base_backup_dir) if os.path.isdir(os.path.join(base_backup_dir, d))]
                                    if subdirs:
                                        base_backup_dir = os.path.join(base_backup_dir, subdirs[0])
                                cmd.append(f'--incremental-basedir={base_backup_dir}')
                            else:
                                logger.error("Could not find base backup for differential backup")
                                backup_type = 'full'  # Fall back to full backup
                else:
                    logger.error(f"Parent backup file not found: {parent_backup.backup_file}")
                    backup_type = 'full'  # Fall back to full backup
        
        # Add any extra options specified for XtraBackup
        if job.xtrabackup_options:
            extra_options = job.xtrabackup_options.split()
            cmd.extend(extra_options)
        
        # Execute backup command
        logger.info(f"Executing {backup_type} backup with {backup_tool}")
        logger.debug(f"Backup command: {' '.join(cmd)}")
        result = subprocess.run(cmd, capture_output=True, text=True)
        
        if result.returncode != 0:
            logger.error(f"Backup error: {result.stderr}")
            return False
            
        # For full backups, prepare the backup to make it consistent
        if backup_type == 'full':
            prepare_cmd = [
                backup_tool,
                '--prepare',
                f'--target-dir={backup_dir}'
            ]
            prepare_result = subprocess.run(prepare_cmd, capture_output=True, text=True)
            if prepare_result.returncode != 0:
                logger.error(f"Backup prepare error: {prepare_result.stderr}")
                return False
        
        # Create a tarball of the backup directory
        target_dir = os.path.dirname(temp_file)
        os.makedirs(target_dir, exist_ok=True)
        
        with tarfile.open(temp_file, "w:gz") as tar:
            tar.add(backup_dir, arcname=os.path.basename(backup_dir))
            
        # If encryption is enabled, encrypt the tarball
        if job.encrypt_backup and job.encryption_type == 'symmetric' and job.encryption_passphrase:
            try:
                from encryption_utils import encrypt_file
                encrypted_file = encrypt_file(
                    temp_file,
                    recipients=None,
                    output_file=f"{temp_file}.gpg",
                    passphrase=job.encryption_passphrase
                )
                if encrypted_file:
                    # Remove the unencrypted file and update the temp_file path
                    os.unlink(temp_file)
                    temp_file = encrypted_file
                else:
                    logger.error("Failed to encrypt backup file")
            except Exception as e:
                logger.error(f"Encryption error: {str(e)}")
            
        # Clean up temporary directories
        try:
            shutil.rmtree(backup_dir)
            if parent_backup_dir:
                shutil.rmtree(os.path.dirname(parent_backup_dir))
            if 'base_backup_dir' in locals() and base_backup_dir:
                shutil.rmtree(os.path.dirname(base_backup_dir))
        except Exception as e:
            logger.warning(f"Failed to clean up temporary directories: {str(e)}")
            
        logger.info(f"Successfully completed {backup_type} backup with {backup_tool}")
        return True
        
    except Exception as e:
        logger.error(f"Backup error: {str(e)}")
        return False

© KUJUNTI.ID