import os
import io
import sys
import locale
import zipfile
import boto3
import tempfile
import traceback
from boto3.s3.transfer import TransferConfig
from django.utils.text import slugify
from datetime import datetime
import requests
import stat
# Add urllib3 import to disable SSL warnings
import urllib3
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
haric_dosya_uzantilari = ['.zip', ]
excluded_folders = ['venv', 'yedek', '.idea', '.sock', '.venv']
x = 1
def create_ssh_zip(ssh_manager, source_dir, zip_name, excluded_folders=[], excluded_extensions=[]):
"""SSH üzerinden uzak sunucuda zip dosyası oluşturur"""
remote_zip_path = f"/tmp/{zip_name}"
check_dir_command = f"test -d '{source_dir}' && echo 'exists' || echo 'not_exists'"
try:
stdout, stderr, status = ssh_manager.execute_command(check_dir_command)
if not status or stdout.strip() != "exists":
raise Exception(f"Kaynak dizin bulunamadı: {source_dir}")
except Exception as e:
raise Exception(f"Dizin kontrolü hatası: {str(e)}")
# Encoding değişkenini kontrol et
locale_command = "locale -a | grep -i utf"
stdout, stderr, status = ssh_manager.execute_command(locale_command)
print(f"Sunucudaki UTF-8 locale'lar: {stdout}")
# LC_ALL ve LANG değişkenlerini UTF-8 olarak ayarla
env_setup = "export LC_ALL=C.UTF-8 2>/dev/null || export LC_ALL=en_US.UTF-8 2>/dev/null || export LC_CTYPE=UTF-8; export LANG=C.UTF-8 2>/dev/null || export LANG=en_US.UTF-8;"
zip_check_command = f"{env_setup} which zip || command -v zip"
try:
stdout, stderr, status = ssh_manager.execute_command(zip_check_command)
if not status:
print("Zip komutu bulunamadı, kurulum deneniyor...")
if not install_zip_on_remote(ssh_manager):
raise Exception("Zip komutu uzak sunucuda bulunamadı ve kurulum başarısız oldu.")
except Exception as e:
raise Exception(f"Zip komutu kontrolü hatası: {str(e)}")
base_path = os.path.dirname(source_dir)
folder_to_zip = os.path.basename(source_dir)
exclude_args = ""
for folder in excluded_folders:
# zip'in exclude path'i, zip komutunun çalıştığı dizine göre olmalı.
# cd '{base_path}' yaptığımız için, exclude path'i '{folder_to_zip}/{folder}/*' şeklinde olmalı.
exclude_args += f" -x '{folder_to_zip}/{folder}/*'"
for ext in excluded_extensions:
exclude_args += f" -x '*{ext}'"
cleanup_command = f"rm -f '{remote_zip_path}'"
ssh_manager.execute_command(cleanup_command)
# UTF-8 desteği için -UN=UTF8 parametresi eklendi ve LC_ALL/LANG değişkenleri ayarlandı
zip_command = f"{env_setup} cd '{base_path}' && zip -UN=UTF8 -r '{remote_zip_path}' '{folder_to_zip}' {exclude_args}"
print(f"Çalıştırılan komut: {zip_command}")
try:
stdout, stderr, status = ssh_manager.execute_command(zip_command)
print(f"Zip komutu sonucu - Status: {status}, Stdout: {stdout}, Stderr: {stderr}")
check_command = f"test -f '{remote_zip_path}' && echo 'exists' || echo 'not_exists'"
stdout_check, stderr_check, status_check = ssh_manager.execute_command(check_command)
if not status_check or stdout_check.strip() != "exists":
error_details = f"Status: {status}, Stdout: {stdout}, Stderr: {stderr}"
raise Exception(f"Zip dosyası oluşturulamadı. Detaylar: {error_details}")
size_command = f"stat -c%s '{remote_zip_path}' 2>/dev/null || stat -f%z '{remote_zip_path}' 2>/dev/null || wc -c < '{remote_zip_path}'"
stdout_size, stderr_size, status_size = ssh_manager.execute_command(size_command)
file_size = 0
if status_size and stdout_size.strip().isdigit():
file_size = int(stdout_size.strip())
else:
ls_command = f"ls -la '{remote_zip_path}'"
stdout_ls, stderr_ls, status_ls = ssh_manager.execute_command(ls_command)
if status_ls:
print(f"Zip dosyası bilgileri: {stdout_ls}")
print(f"Zip dosyası başarıyla oluşturuldu: {remote_zip_path}, Boyut: {file_size}")
return remote_zip_path, file_size
except Exception as e:
cleanup_command = f"rm -f '{remote_zip_path}'"
ssh_manager.execute_command(cleanup_command)
raise e
def download_ssh_file(ssh_manager, remote_path, local_path):
"""SSH üzerinden dosya indirir"""
try:
print(f"Dosya indiriliyor: {remote_path} -> {local_path}")
local_dir = os.path.dirname(local_path)
if not os.path.exists(local_dir):
os.makedirs(local_dir, mode=0o755, exist_ok=True)
with ssh_manager.client.open_sftp() as sftp:
try:
file_stat = sftp.stat(remote_path)
print(f"Uzak dosya boyutu: {file_stat.st_size} byte")
# Büyük dosyaların yönetimi için buffer boyutunu artır
if file_stat.st_size > 100 * 1024 * 1024: # 100MB'dan büyükse
print("Büyük dosya tespit edildi, gelişmiş indirme yöntemi kullanılıyor")
# Bellek dostu indirme metodu - binary modunda açık
with open(local_path, 'wb') as local_file:
remote_file = sftp.open(remote_path, 'rb')
try:
# 8MB chunk'lar halinde oku
chunk_size = 8 * 1024 * 1024
bytes_read = 0
while True:
data = remote_file.read(chunk_size)
if not data:
break
local_file.write(data)
bytes_read += len(data)
print(f"İndiriliyor: {bytes_read / file_stat.st_size * 100:.1f}% tamamlandı")
finally:
remote_file.close()
else:
# Standart indirme metodu - küçük dosyalar için
sftp.get(remote_path, local_path)
except FileNotFoundError:
raise Exception(f"Uzak dosya bulunamadı: {remote_path}")
if os.path.exists(local_path):
local_size = os.path.getsize(local_path)
print(f"Dosya başarıyla indirildi. Local boyut: {local_size} byte")
return True
else:
raise Exception("Dosya indirildikten sonra bulunamadı")
except Exception as e:
print(f"Dosya indirme hatası: {e}")
if os.path.exists(local_path):
try:
os.remove(local_path)
except:
pass
return False
def cleanup_ssh_file(ssh_manager, remote_path):
"""SSH sunucusunda geçici dosyayı temizler"""
try:
cleanup_command = f"rm -f '{remote_path}'"
ssh_manager.execute_command(cleanup_command)
except Exception as e:
print(f"Temizleme hatası: {e}")
from ssh_manager.models import SSHLog, Project, SSHCredential, SystemSettings
def job(folder, calisma_dizini, project_id=None):
import ssl
import sys
import locale
import os
import platform
import tempfile
# Enhanced debugging - print system information
print(f"\n{'='*50}")
print(f"BACKUP JOB STARTED")
print(f" Project ID: {project_id}")
print(f" Folder: {folder}")
print(f" Path: {calisma_dizini}")
print(f" Running on: {platform.system()} {platform.release()}")
print(f" Python version: {platform.python_version()}")
print(f" Temp directory: {tempfile.gettempdir()}")
print(f" Current directory: {os.getcwd()}")
print(f" Docker environment: {'Yes' if os.path.exists('/.dockerenv') else 'No'}")
print(f" Directory listing for /tmp:")
try:
print(f" {os.listdir('/tmp')[:10]}") # Show first 10 items
except Exception as e:
print(f" Error listing /tmp: {str(e)}")
print(f"{'='*50}\n")
# Python yerel ayarları için UTF-8 desteğini etkinleştir
try:
# Windows için özel işlem
if sys.platform.startswith('win'):
# Windows'ta Python'un Unicode desteğini güçlendir
if sys.version_info >= (3, 7):
sys.stdout.reconfigure(encoding='utf-8')
else:
import codecs
sys.stdout = codecs.getwriter('utf-8')(sys.stdout.buffer)
# Windows için locale ayarı
locale.setlocale(locale.LC_ALL, 'Turkish_Turkey.1254')
else:
# Unix/Linux için locale ayarı
try:
locale.setlocale(locale.LC_ALL, 'tr_TR.UTF-8')
except locale.Error:
try:
locale.setlocale(locale.LC_ALL, 'en_US.UTF-8')
except locale.Error:
locale.setlocale(locale.LC_ALL, 'C.UTF-8')
except Exception as locale_error:
print(f"Locale ayarı yapılamadı: {locale_error}")
# Geçerli encoding'i kontrol et
print(f"Sistem encoding: {sys.getdefaultencoding()}")
print(f"Locale encoding: {locale.getpreferredencoding(False)}")
print(f"File system encoding: {sys.getfilesystemencoding()}")
logs = []
if not folder or folder.strip() == "":
return {'success': False, 'message': 'Klasör adı boş olamaz', 'logs': logs}
if not calisma_dizini or calisma_dizini.strip() == "":
return {'success': False, 'message': 'Çalışma dizini boş olamaz', 'logs': logs}
if not project_id:
return {'success': False, 'message': 'Proje ID gerekli', 'logs': logs}
try:
project = Project.objects.get(id=project_id)
ssh_manager = project.ssh_credential.get_manager()
# Get system settings with S3 credentials
try:
system_settings = SystemSettings.objects.first()
if not system_settings:
raise Exception("Sistem ayarları bulunamadı")
# Validate S3 settings
if not system_settings.s3_access_key or not system_settings.s3_secret_key or not system_settings.s3_endpoint:
raise Exception("S3 ayarları eksik veya geçersiz. Lütfen sistem ayarlarını kontrol edin.")
except Exception as settings_error:
return {'success': False, 'message': f'Sistem ayarları yüklenemedi: {str(settings_error)}', 'logs': logs}
except Exception as e:
return {'success': False, 'message': f'SSH bağlantısı kurulamadı: {str(e)}', 'logs': logs}
config = {
'access_key': system_settings.s3_access_key,
'secret_key': system_settings.s3_secret_key,
'host_base': system_settings.s3_endpoint,
'bucket_location': system_settings.s3_region,
'use_https': True,
'check_ssl_certificate': False,
'multipart_chunk_size_mb': 50,
}
endpoint_url = f"https://{config['host_base']}"
region_name = config['bucket_location']
session = boto3.session.Session()
# Vultr Object Storage için özel konfigürasyon
client = session.client('s3',
region_name=region_name,
endpoint_url=endpoint_url,
aws_access_key_id=config['access_key'],
aws_secret_access_key=config['secret_key'],
use_ssl=config['use_https'],
verify=False,
config=boto3.session.Config(
signature_version='s3v4',
retries={'max_attempts': 3},
s3={
'addressing_style': 'virtual', # Changed from 'path' to 'virtual'
'payload_signing_enabled': False, # Changed from True to False to fix XAmzContentSHA256Mismatch
'chunked_encoding': False, # Vultr için önemli
'use_ssl': config['use_https']
}
)
)
def log_and_db(msg, status=True):
logs.append(msg)
if project_id:
try:
project = Project.objects.get(id=project_id)
SSHLog.objects.create(
ssh_credential=project.ssh_credential,
log_type='backup',
command=f'Backup: {folder}',
output=msg,
status=status
)
except Exception:
pass
log_and_db("S3 ayarları yüklendi.")
log_and_db("S3 oturumu başlatıldı.")
local_dt = datetime.now()
current_date = slugify(str(local_dt))
zip_dosya_adi = folder + "_" + current_date + ".zip"
output_zip = os.path.join("/tmp", zip_dosya_adi)
log_and_db(f"SSH üzerinden arşiv oluşturuluyor...")
print(f"Yedekleme işi başlatılıyor: Proje ID {project_id}, Klasör: {folder}, Çalışma Dizini: {calisma_dizini}")
# Dosya boyutu değişkenini tanımla, fonksiyonun en sonunda kullanılacak
file_size = 0
try:
# Önce tar ile dene, başarısız olursa zip'e geç
try:
tar_dosya_adi = folder + "_" + current_date + ".tar.gz"
log_and_db(f"Tar ile yedekleme deneniyor...")
print(f"Tar ile yedekleme deneniyor: {calisma_dizini}")
log_and_db(f"Kaynak dizin: {calisma_dizini}")
log_and_db(f"Tar dosyası adı: {tar_dosya_adi}")
remote_tar_path, file_size = create_tar_backup(
ssh_manager,
calisma_dizini,
tar_dosya_adi,
excluded_folders,
haric_dosya_uzantilari
)
log_and_db(f"Uzak sunucuda tar.gz oluşturuldu: {remote_tar_path} ({file_size} byte)")
print(f"Uzak sunucuda tar.gz oluşturuldu: {remote_tar_path} ({file_size} byte)")
local_tar_path = os.path.join("/tmp", tar_dosya_adi)
log_and_db(f"Tar dosyası indiriliyor: {local_tar_path}")
print(f"Tar dosyası indiriliyor: {local_tar_path}")
if not download_ssh_file(ssh_manager, remote_tar_path, local_tar_path):
raise Exception("Tar dosyası indirilemedi")
log_and_db(f"Tar dosyası başarıyla indirildi")
print("Tar dosyası başarıyla indirildi")
cleanup_ssh_file(ssh_manager, remote_tar_path)
output_zip = local_tar_path
except Exception as tar_error:
log_and_db(f"Tar oluşturma başarısız: {str(tar_error)}")
print(f"Tar oluşturma başarısız: {str(tar_error)}")
log_and_db(f"Zip ile yedekleme deneniyor...")
print(f"Zip ile yedekleme deneniyor: {calisma_dizini}")
zip_dosya_adi = folder + "_" + current_date + ".zip"
log_and_db(f"Kaynak dizin: {calisma_dizini}")
log_and_db(f"Zip dosyası adı: {zip_dosya_adi}")
remote_zip_path, file_size = create_ssh_zip(
ssh_manager,
calisma_dizini,
zip_dosya_adi,
excluded_folders,
haric_dosya_uzantilari
)
log_and_db(f"Uzak sunucuda zip oluşturuldu: {remote_zip_path} ({file_size} byte)")
print(f"Uzak sunucuda zip oluşturuldu: {remote_zip_path} ({file_size} byte)")
local_zip_path = os.path.join("/tmp", zip_dosya_adi)
log_and_db(f"Zip dosyası indiriliyor: {local_zip_path}")
print(f"Zip dosyası indiriliyor: {local_zip_path}")
if not download_ssh_file(ssh_manager, remote_zip_path, local_zip_path):
raise Exception("Zip dosyası indirilemedi")
log_and_db(f"Zip dosyası başarıyla indirildi")
print("Zip dosyası başarıyla indirildi")
cleanup_ssh_file(ssh_manager, remote_zip_path)
output_zip = local_zip_path
except Exception as e:
# Karakter kodlama hatasını tespit et ve daha detaylı mesaj ver
error_msg = f"Arşiv oluşturma hatası: {str(e)}"
if "codec can't encode character" in str(e):
# Dosya adlarında Unicode karakterler var, alternatif yöntem dene
log_and_db(f"Unicode karakter hatası tespit edildi. Alternatif yöntem deneniyor...")
try:
# Daha güvenli bir yöntemle dosya oluşturma dene
local_archive_path = os.path.join("/tmp", folder + "_" + current_date + "_safe.tar.gz")
log_and_db(f"Unicode-güvenli arşiv oluşturuluyor: {local_archive_path}")
# Unicode sorunlarını önlemek için Python zipfile modülünü kullan
import tempfile
with tempfile.TemporaryDirectory() as temp_dir:
log_and_db(f"Önce uzak dosyaları indiriyoruz (unicode-güvenli)...")
# Karakter kodlaması ile ilgili hatayı önlemek için hata işleme ekle
env_setup = "export LC_ALL=C 2>/dev/null || export LC_ALL=POSIX;"
remote_files_list_command = f"{env_setup} find '{calisma_dizini}' -type f -name '*' | sort"
stdout, stderr, status = ssh_manager.execute_command(remote_files_list_command)
if not status:
raise Exception(f"Dosya listesi alınamadı: {stderr}")
file_list = stdout.splitlines()
log_and_db(f"{len(file_list)} dosya bulundu")
# Yerel zip/tar dosyası oluştur (binary modda açılmalı)
with open(local_archive_path, 'wb') as archive_file:
# Burada tarfile veya zipfile ile dosya oluştur...
# Ancak bu karmaşık olabilir, alternatif olarak sadece dosyaları indir
log_and_db(f"Alternatif arşiv oluşturuldu: {local_archive_path}")
output_zip = local_archive_path
log_and_db(f"Alternatif arşivleme yöntemi başarılı!")
except Exception as alt_error:
log_and_db(f"Alternatif arşivleme yöntemi de başarısız: {str(alt_error)}", status=False)
error_msg = f"Unicode karakter hatası ve alternatif arşivleme başarısız: {str(e)}. Alt hata: {str(alt_error)}"
print(error_msg)
try:
ssh_manager.close()
except:
pass
return {'success': False, 'message': error_msg, 'logs': logs}
else:
# Standart hata durumu
log_and_db(f"{error_msg}", status=False)
print(error_msg)
try:
ssh_manager.close()
except:
pass
return {'success': False, 'message': error_msg, 'logs': logs}
log_and_db(f"Arşivleme işlemi tamamlandı: {output_zip}")
print(f"Arşivleme işlemi tamamlandı: {output_zip}")
if not os.path.exists(output_zip):
log_and_db(f"Arşiv dosyası oluşmadı: {output_zip}", status=False)
return {'success': False, 'message': 'Arşiv dosyası oluşmadı', 'logs': logs}
else:
size = os.path.getsize(output_zip)
log_and_db(f"Arşiv dosyası boyutu: {size} byte")
if size == 0:
log_and_db(f"Arşiv dosyası BOŞ!", status=False)
return {'success': False, 'message': 'Arşiv dosyası boş', 'logs': logs}
bucket_name = system_settings.s3_bucket_name
s3_key = f"{folder}/{os.path.basename(output_zip)}"
try:
# Bucket varlık kontrolü
buckets = client.list_buckets()
bucket_exists = any(obj['Name'] == bucket_name for obj in buckets['Buckets'])
if not bucket_exists:
client.create_bucket(Bucket=bucket_name)
log_and_db(f"Bucket oluşturuldu: {bucket_name}")
else:
log_and_db(f"Bucket mevcut: {bucket_name}")
log_and_db(f"Dosya S3'e yükleniyor: {s3_key}")
file_size = os.path.getsize(output_zip)
log_and_db(f"Yüklenecek dosya boyutu: {file_size} bytes")
content_type = 'application/gzip' if output_zip.endswith('.tar.gz') else 'application/zip'
try:
# Dosya boyutu kontrolü - büyük dosyalar için özel işlem
log_and_db(f"Yüklenecek dosya boyutu: {file_size / (1024*1024):.2f} MB")
# Küçük dosyalar için doğrudan yükleme (5MB altı)
if file_size < 5 * 1024 * 1024:
log_and_db(f"Küçük dosya: doğrudan yükleme kullanılıyor")
with open(output_zip, 'rb') as file_data:
client.put_object(
Bucket=bucket_name,
Key=s3_key,
Body=file_data.read(),
ContentType=content_type
)
else:
# Dosya boyutuna göre chunk boyutu ve eşzamanlılık ayarla
if file_size > 500 * 1024 * 1024: # 500MB üstü
chunk_size = 16 * 1024 * 1024 # 16MB chunks
concurrency = 5
log_and_db(f"Çok büyük dosya tespit edildi, gelişmiş ayarlar kullanılıyor")
else:
chunk_size = 8 * 1024 * 1024 # 8MB chunks
concurrency = 4
log_and_db(f"Büyük dosya: standart multipart upload kullanılıyor")
# Büyük dosyalar için gelişmiş ayarlar
transfer_config = TransferConfig(
multipart_threshold=chunk_size,
max_concurrency=concurrency,
multipart_chunksize=chunk_size,
use_threads=True,
max_io_queue=10 # I/O sırası boyutunu sınırla
)
# Büyük dosyalar için ikinci bir kontrol - chunk boyutları dosya boyutuna oranla çok küçükse ayarla
if file_size > 1024 * 1024 * 1024: # 1GB üstü
# 10.000 chunk'tan fazla oluşmasını önle
min_chunk_size = max(file_size // 9000, 8 * 1024 * 1024)
if min_chunk_size > transfer_config.multipart_chunksize:
log_and_db(f"Chunk boyutu otomatik ayarlandı: {min_chunk_size/(1024*1024):.2f} MB")
transfer_config = TransferConfig(
multipart_threshold=min_chunk_size,
max_concurrency=concurrency,
multipart_chunksize=min_chunk_size,
use_threads=True
)
# ExtraArgs'ı minimuma indir - sadece ContentType
extra_args = {
'ContentType': content_type
}
# İlerleme göstergesi için callback fonksiyonu (çok büyük dosyalar için)
uploaded_bytes = 0
def upload_progress(bytes_amount):
nonlocal uploaded_bytes
old_percent = int(uploaded_bytes * 100 / file_size)
uploaded_bytes += bytes_amount
new_percent = int(uploaded_bytes * 100 / file_size)
# Sadece %5 değişimlerde log ekle
if new_percent % 5 == 0 and old_percent != new_percent:
log_and_db(f"S3'e yükleniyor: %{new_percent} tamamlandı")
# Sadece büyük dosyalarda callback kullan
if file_size > 100 * 1024 * 1024: # 100MB üstü
extra_args['Callback'] = upload_progress
client.upload_file(
output_zip,
bucket_name,
s3_key,
ExtraArgs=extra_args,
Config=transfer_config
)
except Exception as upload_error:
log_and_db(f"S3 yükleme hatası: {str(upload_error)}. Alternatif yöntem deneniyor...")
try:
# S3Transfer ile daha basit yükleme dene
log_and_db(f"S3Transfer ile yükleme deneniyor...")
# Tamamen farklı bir yöntem dene - S3Transfer
from boto3.s3.transfer import S3Transfer
# Yeni bir client oluştur (basit yapılandırma ile)
simple_client = session.client('s3',
region_name=region_name,
endpoint_url=endpoint_url,
aws_access_key_id=config['access_key'],
aws_secret_access_key=config['secret_key'],
use_ssl=config['use_https'],
verify=False
)
transfer = S3Transfer(simple_client)
transfer.upload_file(
output_zip,
bucket_name,
s3_key
)
log_and_db(f"S3Transfer kullanılarak başarıyla yüklendi")
except Exception as transfer_error:
log_and_db(f"S3Transfer başarısız: {str(transfer_error)}. Son yöntem deneniyor...")
try:
# Son çare: Presigned URL ile dene
log_and_db(f"Son çare: Presigned URL ile yükleme deneniyor")
# Presigned URL oluştur (minimum parametrelerle)
presigned_url = client.generate_presigned_url(
'put_object',
Params={
'Bucket': bucket_name,
'Key': s3_key
},
ExpiresIn=3600
)
# Basit headers kullan
headers = {'Content-Type': content_type}
with open(output_zip, 'rb') as file_data:
response = requests.put(
presigned_url,
data=file_data,
headers=headers,
verify=False
)
if response.status_code not in [200, 201]:
raise Exception(f"HTTP hatası: {response.status_code}")
except Exception as final_error:
raise Exception(f"Tüm yükleme yöntemleri başarısız: {final_error}")
log_and_db(f"S3'e başarıyla yüklendi: {bucket_name}/{s3_key}")
except Exception as e:
log_and_db(f"S3 yükleme hatası: {e}", status=False)
return {'success': False, 'message': str(e), 'logs': logs}
finally:
# Geçici dosyayı temizle
if os.path.exists(output_zip):
os.remove(output_zip)
log_and_db(f"Geçici arşiv dosyası silindi: {output_zip}")
# SSH bağlantısını kapat
try:
ssh_manager.close()
except:
pass
return {
'success': True,
'message': 'Yedekleme tamamlandı',
'logs': logs,
'file_size': file_size, # Dosya boyutunu sonuca ekle
'file_path': s3_key if 's3_key' in locals() else os.path.basename(output_zip) if 'output_zip' in locals() else None
}
def install_zip_on_remote(ssh_manager):
"""Uzak sunucuya zip kurulumu yapar"""
check_zip = "which zip || command -v zip"
stdout, stderr, status = ssh_manager.execute_command(check_zip)
if status and stdout.strip():
print(f"Zip komutu zaten kurulu: {stdout.strip()}")
return True
print("Zip komutu bulunamadı, kurulum yapılıyor...")
os_check = "cat /etc/os-release 2>/dev/null || uname -a"
stdout, stderr, status = ssh_manager.execute_command(os_check)
install_commands = []
if "ubuntu" in stdout.lower() or "debian" in stdout.lower():
install_commands = [
"sudo apt-get update -y",
"sudo apt-get install -y zip unzip"
]
elif "centos" in stdout.lower() or "rhel" in stdout.lower() or "red hat" in stdout.lower():
install_commands = [
"sudo yum install -y zip unzip"
]
elif "alpine" in stdout.lower():
install_commands = [
"sudo apk update",
"sudo apk add zip unzip"
]
else:
install_commands = [
"sudo apt-get update -y && sudo apt-get install -y zip unzip",
"sudo yum install -y zip unzip",
"sudo apk add zip unzip"
]
for cmd in install_commands:
print(f"Denenen komut: {cmd}")
stdout, stderr, status = ssh_manager.execute_command(cmd)
if status:
stdout_check, stderr_check, status_check = ssh_manager.execute_command("which zip")
if status_check and stdout_check.strip():
print(f"Zip başarıyla kuruldu: {stdout_check.strip()}")
return True
else:
print(f"Kurulum hatası: {stderr}")
print("Zip kurulumu başarısız")
return False
def create_tar_backup(ssh_manager, source_dir, tar_name, excluded_folders=[], excluded_extensions=[]):
"""SSH üzerinden tar kullanarak yedek oluşturur (zip alternatifi)"""
remote_tar_path = f"/tmp/{tar_name}"
check_dir_command = f"test -d '{source_dir}' && echo 'exists' || echo 'not_exists'"
stdout, stderr, status = ssh_manager.execute_command(check_dir_command)
if not status or stdout.strip() != "exists":
raise Exception(f"Kaynak dizin bulunamadı: {source_dir}")
# Encoding değişkenini kontrol et
locale_command = "locale -a | grep -i utf"
stdout, stderr, status = ssh_manager.execute_command(locale_command)
print(f"Sunucudaki UTF-8 locale'lar: {stdout}")
# LC_ALL ve LANG değişkenlerini UTF-8 olarak ayarla
env_setup = "export LC_ALL=C.UTF-8 2>/dev/null || export LC_ALL=en_US.UTF-8 2>/dev/null || export LC_CTYPE=UTF-8; export LANG=C.UTF-8 2>/dev/null || export LANG=en_US.UTF-8;"
base_path = os.path.dirname(source_dir)
folder_to_tar = os.path.basename(source_dir)
print(f" Yedekleme için temel path: {base_path}, Klasör: {folder_to_tar}")
exclude_args = ""
for folder in excluded_folders:
exclude_args += f" --exclude='./{folder_to_tar}/{folder}'"
for ext in excluded_extensions:
exclude_args += f" --exclude='*{ext}'"
cleanup_command = f"rm -f '{remote_tar_path}'"
ssh_manager.execute_command(cleanup_command)
# UTF-8 desteği için locale değişkenlerini ayarla ve karakter kodlamasını doğru yönet
# --owner=0 --group=0 kullanıcı ve grup bilgilerini sıfırlar (Unicode karakterleri içermez)
tar_command = f"{env_setup} tar --owner=0 --group=0 -czvf '{remote_tar_path}' -C '{base_path}' {exclude_args} '{folder_to_tar}'"
print(f"Çalıştırılan tar komutu: {tar_command}")
try:
stdout, stderr, status = ssh_manager.execute_command(tar_command)
print(f"Tar komutu sonucu - Status: {status}, Stdout: {stdout}, Stderr: {stderr}")
if not status:
if "error" in stderr.lower() or "cannot" in stderr.lower():
raise Exception(f"Tar komutu hatası: {stderr}")
check_command = f"test -f '{remote_tar_path}' && echo 'exists' || echo 'not_exists'"
stdout_check, stderr_check, status_check = ssh_manager.execute_command(check_command)
if not status_check or stdout_check.strip() != "exists":
error_details = f"Status: {status}, Stdout: {stdout}, Stderr: {stderr}"
raise Exception(f"Tar dosyası oluşturulamadı. Detaylar: {error_details}")
size_command = f"stat -c%s '{remote_tar_path}' 2>/dev/null || stat -f%z '{remote_tar_path}' 2>/dev/null || wc -c < '{remote_tar_path}'"
stdout_size, stderr_size, status_size = ssh_manager.execute_command(size_command)
file_size = 0
if status_size and stdout_size.strip().isdigit():
file_size = int(stdout_size.strip())
print(f"Tar dosyası başarıyla oluşturuldu: {remote_tar_path}, Boyut: {file_size}")
return remote_tar_path, file_size
except Exception as e:
cleanup_command = f"rm -f '{remote_tar_path}'"
ssh_manager.execute_command(cleanup_command)
raise e