File: //home/gisha985666/htdocs/BackupSystem/wp_backup.py
#!/usr/bin/env python3
import os
import sys
import zipfile
import shutil
import subprocess
import logging
import json
from datetime import datetime
from pathlib import Path
import configparser
try:
from googleapiclient.discovery import build
from googleapiclient.http import MediaFileUpload
from google.oauth2.service_account import Credentials
except ImportError:
print("Error: Google API client libraries not installed.")
print("Run: pip install google-api-python-client google-auth")
sys.exit(1)
class WordPressBackup:
def __init__(self, config_file='config.ini'):
self.config = configparser.ConfigParser()
self.config.read(config_file)
# Setup logging
log_level = self.config.get('general', 'log_level', fallback='INFO')
logging.basicConfig(
level=getattr(logging, log_level),
format='%(asctime)s - %(levelname)s - %(message)s',
handlers=[
logging.FileHandler('wp_backup.log'),
logging.StreamHandler()
]
)
self.logger = logging.getLogger(__name__)
# Configuration
self.wp_path = self.config.get('wordpress', 'wp_path')
self.backup_dir = self.config.get('general', 'backup_dir', fallback='/tmp/wp_backups')
self.keep_local_files = self.config.getboolean('general', 'keep_local_files', fallback=False)
# Database config
self.db_host = self.config.get('database', 'host')
self.db_name = self.config.get('database', 'name')
self.db_user = self.config.get('database', 'user')
self.db_password = self.config.get('database', 'password')
# Google Drive config
self.credentials_file = self.config.get('google_drive', 'credentials_file')
self.drive_folder_id = self.config.get('google_drive', 'folder_id', fallback=None)
# Ensure backup directory exists
Path(self.backup_dir).mkdir(parents=True, exist_ok=True)
# Initialize Google Drive service
self.drive_service = self._init_drive_service()
def _init_drive_service(self):
"""Initialize Google Drive API service"""
try:
credentials = Credentials.from_service_account_file(
self.credentials_file,
scopes=['https://www.googleapis.com/auth/drive.file']
)
return build('drive', 'v3', credentials=credentials)
except Exception as e:
self.logger.error(f"Failed to initialize Google Drive service: {e}")
return None
def create_files_backup(self):
"""Create zip backup of WordPress files"""
self.logger.info("Starting WordPress files backup...")
timestamp = datetime.now().strftime('%Y%m%d_%H%M%S')
zip_filename = f"wp_files_backup_{timestamp}.zip"
zip_path = os.path.join(self.backup_dir, zip_filename)
try:
with zipfile.ZipFile(zip_path, 'w', zipfile.ZIP_DEFLATED) as zipf:
for root, dirs, files in os.walk(self.wp_path):
# Skip backup directory if it's inside wp_path
if self.backup_dir in root:
continue
for file in files:
file_path = os.path.join(root, file)
arcname = os.path.relpath(file_path, self.wp_path)
zipf.write(file_path, arcname)
self.logger.info(f"Files backup created: {zip_path}")
return zip_path
except Exception as e:
self.logger.error(f"Failed to create files backup: {e}")
return None
def create_database_backup(self):
"""Create database backup using mysqldump"""
self.logger.info("Starting database backup...")
timestamp = datetime.now().strftime('%Y%m%d_%H%M%S')
sql_filename = f"wp_db_backup_{timestamp}.sql"
sql_path = os.path.join(self.backup_dir, sql_filename)
zip_filename = f"wp_db_backup_{timestamp}.zip"
zip_path = os.path.join(self.backup_dir, zip_filename)
try:
# Create SQL dump
cmd = [
'mysqldump',
f'--host={self.db_host}',
f'--user={self.db_user}',
f'--password={self.db_password}',
'--single-transaction',
'--routines',
'--triggers',
self.db_name
]
with open(sql_path, 'w') as f:
subprocess.run(cmd, stdout=f, check=True)
# Compress SQL file
with zipfile.ZipFile(zip_path, 'w', zipfile.ZIP_DEFLATED) as zipf:
zipf.write(sql_path, sql_filename)
# Remove uncompressed SQL file
os.remove(sql_path)
self.logger.info(f"Database backup created: {zip_path}")
return zip_path
except subprocess.CalledProcessError as e:
self.logger.error(f"Failed to create database backup: {e}")
return None
except Exception as e:
self.logger.error(f"Unexpected error during database backup: {e}")
return None
def upload_to_drive(self, file_path):
"""Upload file to Google Drive"""
if not self.drive_service:
self.logger.error("Google Drive service not initialized")
return False
self.logger.info(f"Uploading {file_path} to Google Drive...")
try:
file_metadata = {
'name': os.path.basename(file_path)
}
if self.drive_folder_id:
file_metadata['parents'] = [self.drive_folder_id]
media = MediaFileUpload(file_path, resumable=True)
file = self.drive_service.files().create(
body=file_metadata,
media_body=media,
fields='id',
supportsAllDrives=True
).execute()
self.logger.info(f"File uploaded successfully. File ID: {file.get('id')}")
return True
except Exception as e:
self.logger.error(f"Failed to upload file to Google Drive: {e}")
return False
def cleanup_local_file(self, file_path):
"""Remove local backup file"""
if not self.keep_local_files:
try:
os.remove(file_path)
self.logger.info(f"Local file removed: {file_path}")
except Exception as e:
self.logger.error(f"Failed to remove local file {file_path}: {e}")
def run_backup(self):
"""Run complete backup process"""
self.logger.info("Starting WordPress backup process...")
success = True
# Backup WordPress files
files_backup_path = self.create_files_backup()
if files_backup_path:
if self.upload_to_drive(files_backup_path):
self.cleanup_local_file(files_backup_path)
else:
success = False
else:
success = False
# Backup database
db_backup_path = self.create_database_backup()
if db_backup_path:
if self.upload_to_drive(db_backup_path):
self.cleanup_local_file(db_backup_path)
else:
success = False
else:
success = False
if success:
self.logger.info("Backup process completed successfully")
else:
self.logger.error("Backup process completed with errors")
return success
def main():
config_file = sys.argv[1] if len(sys.argv) > 1 else 'config.ini'
if not os.path.exists(config_file):
print(f"Error: Configuration file '{config_file}' not found")
sys.exit(1)
backup = WordPressBackup(config_file)
success = backup.run_backup()
sys.exit(0 if success else 1)
if __name__ == '__main__':
main()