607 lines
28 KiB
Python
607 lines
28 KiB
Python
import paramiko
|
||
import logging
|
||
import os
|
||
import tempfile
|
||
from django.utils import timezone
|
||
from django.template.loader import render_to_string
|
||
|
||
logger = logging.getLogger(__name__)
|
||
|
||
class SSHManager:
|
||
def __init__(self, ssh_credential):
|
||
self.ssh_credential = ssh_credential
|
||
self.client = None
|
||
self.connect()
|
||
logger.info(f'SSHManager başlatıldı: {ssh_credential.hostname}')
|
||
|
||
def connect(self):
|
||
"""SSH bağlantısı kur"""
|
||
try:
|
||
self.client = paramiko.SSHClient()
|
||
self.client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
|
||
self.client.connect(
|
||
hostname=self.ssh_credential.hostname,
|
||
username=self.ssh_credential.username,
|
||
password=self.ssh_credential.password,
|
||
port=self.ssh_credential.port or 22,
|
||
look_for_keys=False,
|
||
allow_agent=False
|
||
)
|
||
return True
|
||
except Exception as e:
|
||
logger.error(f'SSH bağlantı hatası: {str(e)}')
|
||
return False
|
||
|
||
def close(self):
|
||
"""SSH bağlantısını kapat"""
|
||
if self.client:
|
||
self.client.close()
|
||
self.client = None
|
||
|
||
def check_connection(self):
|
||
"""SSH bağlantısını kontrol et"""
|
||
try:
|
||
if not self.client:
|
||
return self.connect()
|
||
self.client.exec_command('echo "Connection test"')
|
||
return True
|
||
except:
|
||
return self.connect()
|
||
|
||
def execute_command(self, command):
|
||
"""
|
||
SSH üzerinden komut çalıştır ve sonuçları döndür
|
||
"""
|
||
try:
|
||
if not self.client:
|
||
self.connect()
|
||
|
||
stdin, stdout, stderr = self.client.exec_command(command)
|
||
exit_status = stdout.channel.recv_exit_status()
|
||
|
||
# Binary veriyi oku
|
||
stdout_data = stdout.read()
|
||
stderr_data = stderr.read()
|
||
|
||
# Farklı encoding'leri dene
|
||
encodings = ['utf-8', 'latin1', 'cp1252', 'iso-8859-9']
|
||
|
||
# stdout için encoding dene
|
||
stdout_str = None
|
||
for enc in encodings:
|
||
try:
|
||
stdout_str = stdout_data.decode(enc)
|
||
break
|
||
except UnicodeDecodeError:
|
||
continue
|
||
|
||
# stderr için encoding dene
|
||
stderr_str = None
|
||
for enc in encodings:
|
||
try:
|
||
stderr_str = stderr_data.decode(enc)
|
||
break
|
||
except UnicodeDecodeError:
|
||
continue
|
||
|
||
# Eğer hiçbir encoding çalışmazsa, latin1 kullan (her byte'ı decode edebilir)
|
||
if stdout_str is None:
|
||
stdout_str = stdout_data.decode('latin1')
|
||
if stderr_str is None:
|
||
stderr_str = stderr_data.decode('latin1')
|
||
|
||
return stdout_str, stderr_str, exit_status == 0
|
||
|
||
except Exception as e:
|
||
logger.exception(f"Komut çalıştırma hatası: {command}")
|
||
return "", str(e), False
|
||
|
||
def download_req_file(self, project):
|
||
"""req.txt dosyasını oku ve geçici dosya olarak kaydet"""
|
||
try:
|
||
# Dosya içeriğini oku
|
||
cmd = f'cat "{project.get_full_path()}/req.txt"'
|
||
stdout, stderr, status = self.execute_command(cmd)
|
||
|
||
if not status:
|
||
logger.error(f"req.txt okunamadı: {stderr}")
|
||
return None
|
||
|
||
# Geçici dosya oluştur
|
||
temp = tempfile.NamedTemporaryFile(mode='w+', delete=False, suffix='.txt')
|
||
temp.write(stdout)
|
||
temp.close()
|
||
|
||
logger.info(f"req.txt temp file created: {temp.name}")
|
||
return temp.name
|
||
|
||
except Exception as e:
|
||
logger.exception(f"Error in download_req_file: {str(e)}")
|
||
return None
|
||
|
||
def delete_project(self, project):
|
||
"""Proje klasörünü sil"""
|
||
try:
|
||
cmd = f'rm -rf "{project.get_full_path()}"'
|
||
stdout, stderr, status = self.execute_command(cmd)
|
||
|
||
if status:
|
||
return True, "Proje başarıyla silindi"
|
||
else:
|
||
return False, f"Silme hatası: {stderr}"
|
||
|
||
except Exception as e:
|
||
return False, str(e)
|
||
|
||
def upload_zip(self, project, zip_file):
|
||
"""ZIP dosyasını yükle ve aç"""
|
||
try:
|
||
# Geçici dizin oluştur
|
||
temp_dir = '/tmp/project_upload'
|
||
mkdir_out, mkdir_err, mkdir_status = self.execute_command(f'rm -rf {temp_dir} && mkdir -p {temp_dir}')
|
||
if not mkdir_status:
|
||
return False, f'Geçici dizin oluşturulamadı: {mkdir_err}'
|
||
|
||
# SFTP bağlantısı
|
||
sftp = self.client.open_sftp()
|
||
|
||
try:
|
||
# ZIP dosyasını yükle
|
||
remote_zip = f"{temp_dir}/{zip_file.name}"
|
||
sftp.putfo(zip_file, remote_zip)
|
||
|
||
# ZIP dosyasını aç
|
||
unzip_cmd = f'''
|
||
cd {temp_dir} && \
|
||
unzip -o "{zip_file.name}" && \
|
||
rm "{zip_file.name}" && \
|
||
mv * "{project.get_full_path()}/" 2>/dev/null || true && \
|
||
cd / && \
|
||
rm -rf {temp_dir}
|
||
'''
|
||
|
||
stdout, stderr, status = self.execute_command(unzip_cmd)
|
||
|
||
if not status:
|
||
return False, f'ZIP açma hatası: {stderr}'
|
||
|
||
return True, "Dosya başarıyla yüklendi"
|
||
|
||
finally:
|
||
sftp.close()
|
||
|
||
except Exception as e:
|
||
return False, str(e)
|
||
|
||
def upload_txt(self, project, txt_file):
|
||
"""TXT dosyasını yükle"""
|
||
try:
|
||
# SFTP bağlantısı
|
||
sftp = self.client.open_sftp()
|
||
|
||
try:
|
||
# Dosya adını belirle
|
||
remote_path = f"{project.get_full_path()}/req.txt"
|
||
|
||
# Dosyayı yükle
|
||
sftp.putfo(txt_file, remote_path)
|
||
|
||
# İzinleri ayarla
|
||
self.execute_command(f'chmod 644 "{remote_path}"')
|
||
|
||
return True, "Dosya başarıyla yüklendi"
|
||
|
||
finally:
|
||
sftp.close()
|
||
|
||
except Exception as e:
|
||
return False, str(e)
|
||
|
||
def create_config_files(self, project):
|
||
"""Tüm konfigürasyon dosyalarını oluşturur"""
|
||
try:
|
||
logger.info(f'"{project.folder_name}" projesi için konfigürasyon dosyaları oluşturuluyor')
|
||
|
||
# Değişkenleri hazırla
|
||
context = {
|
||
'project_name': project.folder_name,
|
||
'project_path': project.get_full_path(),
|
||
'domain_name': project.url
|
||
}
|
||
logger.info('Konfigürasyon şablonları için context hazırlandı')
|
||
|
||
# Konfigürasyon içeriklerini hazırla
|
||
configs = {
|
||
'nginx.conf': render_to_string('ssh_manager/nginx.conf.template', context),
|
||
'supervisor.conf': render_to_string('ssh_manager/supervisor.conf.template', context),
|
||
'wsgi_conf': render_to_string('ssh_manager/wsgi.conf.template', context)
|
||
}
|
||
logger.info('Konfigürasyon şablonları render edildi')
|
||
|
||
# WSGI dosyasını proje dizininde oluştur
|
||
logger.info('WSGI dosyası oluşturuluyor')
|
||
wsgi_cmd = f'cat > "{project.get_full_path()}/wsgi_conf" << "EOF"\n{configs["wsgi_conf"]}\nEOF'
|
||
stdout, stderr, status = self.execute_command(wsgi_cmd)
|
||
|
||
if not status:
|
||
logger.error(f'WSGI dosyası oluşturma hatası: {stderr}')
|
||
raise Exception(f'WSGI dosyası oluşturulamadı: {stderr}')
|
||
logger.info('WSGI dosyası başarıyla oluşturuldu')
|
||
|
||
# WSGI için izinleri ayarla
|
||
logger.info('WSGI dosyası için çalıştırma izinleri ayarlanıyor')
|
||
chmod_cmd = f'chmod +x "{project.get_full_path()}/wsgi_conf"'
|
||
stdout, stderr, status = self.execute_command(chmod_cmd)
|
||
if not status:
|
||
logger.error(f'WSGI izin ayarlama hatası: {stderr}')
|
||
raise Exception(f'WSGI için izinler ayarlanamadı: {stderr}')
|
||
logger.info('WSGI dosyası için izinler başarıyla ayarlandı')
|
||
|
||
# Nginx konfigürasyonunu direkt hedef konumunda oluştur
|
||
if project.url:
|
||
logger.info('Nginx konfigürasyonu ayarlanıyor')
|
||
nginx_target = f'/etc/nginx/sites-available/{project.url}'
|
||
nginx_enabled = f'/etc/nginx/sites-enabled/{project.url}'
|
||
|
||
# Eski konfigürasyonları temizle
|
||
logger.info('Eski Nginx konfigürasyonları temizleniyor')
|
||
self.execute_command(f'sudo rm -f {nginx_target} {nginx_enabled}')
|
||
|
||
# Yeni konfigürasyonu oluştur
|
||
logger.info(f'Nginx konfigürasyonu "{nginx_target}" konumunda oluşturuluyor')
|
||
nginx_cmd = f'sudo bash -c \'cat > "{nginx_target}" << "EOF"\n{configs["nginx.conf"]}\nEOF\''
|
||
stdout, stderr, status = self.execute_command(nginx_cmd)
|
||
|
||
if not status:
|
||
logger.error(f'Nginx konfigürasyon oluşturma hatası: {stderr}')
|
||
raise Exception(f'Nginx konfigürasyonu oluşturulamadı: {stderr}')
|
||
logger.info('Nginx konfigürasyonu başarıyla oluşturuldu')
|
||
|
||
# İzinleri ayarla
|
||
logger.info('Nginx konfigürasyonu için izinler ayarlanıyor')
|
||
self.execute_command(f'sudo chown root:root "{nginx_target}"')
|
||
self.execute_command(f'sudo chmod 644 "{nginx_target}"')
|
||
logger.info('Nginx konfigürasyonu için izinler başarıyla ayarlandı')
|
||
|
||
# Symbolic link oluştur
|
||
logger.info('Nginx symbolic link oluşturuluyor')
|
||
link_cmd = f'sudo ln -sf "{nginx_target}" "{nginx_enabled}"'
|
||
stdout, stderr, status = self.execute_command(link_cmd)
|
||
|
||
if not status:
|
||
logger.error(f'Nginx symbolic link oluşturma hatası: {stderr}')
|
||
raise Exception(f'Nginx symbolic link oluşturulamadı: {stderr}')
|
||
logger.info('Nginx symbolic link başarıyla oluşturuldu')
|
||
|
||
# Supervisor konfigürasyonunu direkt hedef konumunda oluştur
|
||
logger.info('Supervisor konfigürasyonu ayarlanıyor')
|
||
supervisor_target = f'/etc/supervisor/conf.d/{project.folder_name}.conf'
|
||
|
||
# Eski konfigürasyonu temizle
|
||
logger.info('Eski Supervisor konfigürasyonu temizleniyor')
|
||
self.execute_command(f'sudo rm -f {supervisor_target}')
|
||
|
||
# Yeni konfigürasyonu oluştur
|
||
logger.info(f'Supervisor konfigürasyonu "{supervisor_target}" konumunda oluşturuluyor')
|
||
supervisor_cmd = f'sudo bash -c \'cat > "{supervisor_target}" << "EOF"\n{configs["supervisor.conf"]}\nEOF\''
|
||
stdout, stderr, status = self.execute_command(supervisor_cmd)
|
||
|
||
if not status:
|
||
logger.error(f'Supervisor konfigürasyon oluşturma hatası: {stderr}')
|
||
raise Exception(f'Supervisor konfigürasyonu oluşturulamadı: {stderr}')
|
||
logger.info('Supervisor konfigürasyonu başarıyla oluşturuldu')
|
||
|
||
# İzinleri ayarla
|
||
logger.info('Supervisor konfigürasyonu için izinler ayarlanıyor')
|
||
self.execute_command(f'sudo chown root:root "{supervisor_target}"')
|
||
self.execute_command(f'sudo chmod 644 "{supervisor_target}"')
|
||
logger.info('Supervisor konfigürasyonu için izinler başarıyla ayarlandı')
|
||
|
||
# Servisleri yeniden yükle
|
||
logger.info('Servisler yeniden başlatılıyor')
|
||
self.execute_command('sudo systemctl reload nginx')
|
||
self.execute_command('sudo supervisorctl reread')
|
||
self.execute_command('sudo supervisorctl update')
|
||
logger.info('Servisler başarıyla yeniden başlatıldı')
|
||
|
||
logger.info('Tüm konfigürasyon işlemleri başarıyla tamamlandı')
|
||
return True, 'Konfigürasyon dosyaları başarıyla oluşturuldu ve konumlandırıldı'
|
||
|
||
except Exception as e:
|
||
logger.error('Konfigürasyon dosyaları oluşturma hatası')
|
||
logger.exception(e)
|
||
return False, str(e)
|
||
|
||
def get_disk_usage(self):
|
||
"""Sunucunun disk kullanım bilgilerini al"""
|
||
try:
|
||
# Ana disk bölümünün kullanım bilgilerini al (genellikle /)
|
||
cmd = "df -h / | tail -n 1 | awk '{print $2,$3,$4,$5}'"
|
||
stdout, stderr, status = self.execute_command(cmd)
|
||
|
||
if status:
|
||
# Çıktıyı parçala: toplam, kullanılan, boş, yüzde
|
||
parts = stdout.strip().split()
|
||
if len(parts) == 4:
|
||
# Yüzde işaretini kaldır ve sayıya çevir
|
||
usage_percent = int(parts[3].replace('%', ''))
|
||
return {
|
||
'total': parts[0],
|
||
'used': parts[1],
|
||
'available': parts[2],
|
||
'usage_percent': usage_percent
|
||
}
|
||
return None
|
||
except Exception as e:
|
||
logger.exception("Disk kullanım bilgisi alınamadı")
|
||
return None
|
||
|
||
def upload_project_zip(self, project, zip_file):
|
||
"""Proje dosyalarını yükle (zip veya txt)"""
|
||
try:
|
||
logger.info(f'"{project.folder_name}" projesi için dosya yükleme başlatıldı')
|
||
|
||
# Başlangıç disk kullanımını al
|
||
initial_disk = self.get_disk_usage()
|
||
if initial_disk:
|
||
logger.info(f'Başlangıç disk kullanımı - Toplam: {initial_disk["total"]}, Kullanılan: {initial_disk["used"]}, Boş: {initial_disk["available"]}')
|
||
|
||
# Dosya uzantısını kontrol et
|
||
file_extension = os.path.splitext(zip_file.name)[1].lower()
|
||
|
||
# Sadece zip ve txt dosyalarına izin ver
|
||
if file_extension not in ['.zip', '.txt']:
|
||
logger.warning(f'Geçersiz dosya uzantısı: {file_extension}')
|
||
return False, "Sadece .zip ve .txt dosyaları yüklenebilir."
|
||
|
||
# Dosyayı yükle
|
||
logger.info('SFTP bağlantısı açılıyor')
|
||
sftp = self.client.open_sftp()
|
||
|
||
try:
|
||
if file_extension == '.txt':
|
||
# TXT dosyası ise direkt req.txt olarak kaydet
|
||
remote_path = f"{project.get_full_path()}/req.txt"
|
||
logger.info('TXT dosyası req.txt olarak yükleniyor')
|
||
|
||
# İlerleme için callback fonksiyonu
|
||
total_size = zip_file.size
|
||
uploaded_size = 0
|
||
start_time = timezone.now()
|
||
last_update = start_time
|
||
|
||
def progress_callback(sent_bytes, remaining_bytes):
|
||
nonlocal uploaded_size, start_time, last_update
|
||
uploaded_size = sent_bytes
|
||
current_time = timezone.now()
|
||
elapsed_time = (current_time - start_time).total_seconds()
|
||
|
||
# Her 0.5 saniyede bir güncelle
|
||
if (current_time - last_update).total_seconds() >= 0.5:
|
||
if elapsed_time > 0:
|
||
speed = uploaded_size / elapsed_time # bytes/second
|
||
percent = (uploaded_size / total_size) * 100
|
||
remaining_size = total_size - uploaded_size
|
||
eta = remaining_size / speed if speed > 0 else 0
|
||
logger.info(f'Upload Progress: {percent:.1f}% - Speed: {speed/1024:.1f} KB/s - ETA: {eta:.1f}s')
|
||
last_update = current_time
|
||
|
||
sftp.putfo(zip_file, remote_path, callback=progress_callback)
|
||
logger.info('TXT dosyası başarıyla yüklendi')
|
||
|
||
# İzinleri ayarla
|
||
self.execute_command(f'chmod 644 "{remote_path}"')
|
||
|
||
# Venv kontrolü yap
|
||
logger.info('Virtual environment kontrol ediliyor')
|
||
venv_exists = self.check_venv_exists(project)
|
||
|
||
if not venv_exists:
|
||
# Venv oluştur
|
||
logger.info('Virtual environment oluşturuluyor')
|
||
venv_cmd = f'cd "{project.get_full_path()}" && python3 -m venv venv'
|
||
stdout, stderr, status = self.execute_command(venv_cmd)
|
||
if not status:
|
||
error_msg = f'Venv oluşturma hatası: {stderr}'
|
||
logger.error(error_msg)
|
||
return False, stderr
|
||
logger.info('Virtual environment başarıyla oluşturuldu')
|
||
else:
|
||
logger.info('Mevcut virtual environment kullanılacak')
|
||
|
||
# Requirements'ları kur
|
||
logger.info('Requirements kuruluyor')
|
||
install_cmd = f'''
|
||
cd "{project.get_full_path()}" && \
|
||
source venv/bin/activate && \
|
||
pip install --upgrade pip 2>&1 && \
|
||
pip install -r req.txt 2>&1
|
||
'''
|
||
stdout, stderr, status = self.execute_command(install_cmd)
|
||
|
||
if not status:
|
||
# Pip çıktısını logla
|
||
error_msg = 'Requirements kurulum hatası'
|
||
logger.error(error_msg)
|
||
logger.error(f'Pip çıktısı:\n{stdout}')
|
||
if stderr:
|
||
logger.error(f'Pip hata çıktısı:\n{stderr}')
|
||
return False, stdout if stdout else stderr
|
||
|
||
# Başarılı pip çıktısını da logla
|
||
logger.info('Requirements başarıyla kuruldu')
|
||
logger.info(f'Pip kurulum çıktısı:\n{stdout}')
|
||
return True, "Requirements dosyası yüklendi ve kuruldu"
|
||
|
||
else: # ZIP dosyası
|
||
# Geçici dizin oluştur
|
||
temp_dir = f'/tmp/project_upload_{project.id}'
|
||
mkdir_cmd = f'rm -rf {temp_dir} && mkdir -p {temp_dir}'
|
||
stdout, stderr, status = self.execute_command(mkdir_cmd)
|
||
if not status:
|
||
return False, f'Geçici dizin oluşturulamadı: {stderr}'
|
||
|
||
# ZIP dosyasını geçici dizine yükle
|
||
remote_zip = f"{temp_dir}/upload.zip"
|
||
logger.info(f'Zip dosyası "{remote_zip}" konumuna yükleniyor')
|
||
|
||
# İlerleme için callback fonksiyonu
|
||
total_size = zip_file.size
|
||
uploaded_size = 0
|
||
start_time = timezone.now()
|
||
last_update = start_time
|
||
|
||
def progress_callback(sent_bytes, remaining_bytes):
|
||
nonlocal uploaded_size, start_time, last_update
|
||
uploaded_size = sent_bytes
|
||
current_time = timezone.now()
|
||
elapsed_time = (current_time - start_time).total_seconds()
|
||
|
||
# Her 0.5 saniyede bir güncelle
|
||
if (current_time - last_update).total_seconds() >= 0.5:
|
||
if elapsed_time > 0:
|
||
speed = uploaded_size / elapsed_time # bytes/second
|
||
percent = (uploaded_size / total_size) * 100
|
||
remaining_size = total_size - uploaded_size
|
||
eta = remaining_size / speed if speed > 0 else 0
|
||
logger.info(f'Upload Progress: {percent:.1f}% - Speed: {speed/1024:.1f} KB/s - ETA: {eta:.1f}s')
|
||
last_update = current_time
|
||
|
||
sftp.putfo(zip_file, remote_zip, callback=progress_callback)
|
||
logger.info('Zip dosyası başarıyla yüklendi')
|
||
|
||
# Zip dosyasını çıkart
|
||
logger.info('Zip dosyası çıkartılıyor')
|
||
unzip_cmd = f'''
|
||
cd "{temp_dir}" && \
|
||
unzip -o upload.zip && \
|
||
rm upload.zip && \
|
||
cp -rf * "{project.get_full_path()}/" && \
|
||
cd / && \
|
||
rm -rf "{temp_dir}"
|
||
'''
|
||
stdout, stderr, status = self.execute_command(unzip_cmd)
|
||
|
||
if not status:
|
||
error_msg = f'Zip çıkartma hatası: {stderr}'
|
||
logger.error(error_msg)
|
||
return False, stderr
|
||
|
||
logger.info('Zip dosyası başarıyla çıkartıldı')
|
||
|
||
# req.txt var mı kontrol et
|
||
logger.info('req.txt dosyası kontrol ediliyor')
|
||
check_req = f'test -f "{project.get_full_path()}/req.txt" && echo "exists"'
|
||
stdout, stderr, status = self.execute_command(check_req)
|
||
|
||
if status and stdout.strip() == "exists":
|
||
logger.info('req.txt bulundu, venv kurulumu başlatılıyor')
|
||
|
||
# Venv kontrolü yap
|
||
logger.info('Virtual environment kontrol ediliyor')
|
||
venv_exists = self.check_venv_exists(project)
|
||
|
||
if not venv_exists:
|
||
# Venv oluştur
|
||
logger.info('Virtual environment oluşturuluyor')
|
||
venv_cmd = f'cd "{project.get_full_path()}" && python3 -m venv venv'
|
||
stdout, stderr, status = self.execute_command(venv_cmd)
|
||
if not status:
|
||
error_msg = f'Venv oluşturma hatası: {stderr}'
|
||
logger.error(error_msg)
|
||
return False, stderr
|
||
logger.info('Virtual environment başarıyla oluşturuldu')
|
||
else:
|
||
logger.info('Mevcut virtual environment kullanılacak')
|
||
|
||
# Requirements'ları kur
|
||
logger.info('Requirements kuruluyor')
|
||
install_cmd = f'''
|
||
cd "{project.get_full_path()}" && \
|
||
source venv/bin/activate && \
|
||
pip install --upgrade pip 2>&1 && \
|
||
pip install -r req.txt 2>&1
|
||
'''
|
||
stdout, stderr, status = self.execute_command(install_cmd)
|
||
|
||
if not status:
|
||
# Pip çıktısını logla
|
||
error_msg = 'Requirements kurulum hatası'
|
||
logger.error(error_msg)
|
||
logger.error(f'Pip çıktısı:\n{stdout}')
|
||
if stderr:
|
||
logger.error(f'Pip hata çıktısı:\n{stderr}')
|
||
return False, stdout if stdout else stderr
|
||
|
||
# Başarılı pip çıktısını da logla
|
||
logger.info('Requirements başarıyla kuruldu')
|
||
logger.info(f'Pip kurulum çıktısı:\n{stdout}')
|
||
return True, "Proje dosyaları yüklendi ve requirements kuruldu"
|
||
|
||
return True, "Proje dosyaları başarıyla yüklendi"
|
||
|
||
finally:
|
||
sftp.close()
|
||
logger.info('SFTP bağlantısı kapatıldı')
|
||
|
||
# Son disk kullanımını al ve değişimi logla
|
||
final_disk = self.get_disk_usage()
|
||
if final_disk:
|
||
logger.info(f'Son disk kullanımı - Toplam: {final_disk["total"]}, Kullanılan: {final_disk["used"]}, Boş: {final_disk["available"]}')
|
||
|
||
except Exception as e:
|
||
logger.exception("Dosya yükleme hatası")
|
||
return False, str(e)
|
||
|
||
def check_venv_exists(self, project):
|
||
"""Virtual environment'ın var olup olmadığını kontrol et"""
|
||
cmd = f'test -d "{project.get_full_path()}/venv" && echo "exists" || echo "not exists"'
|
||
stdout, stderr, status = self.execute_command(cmd)
|
||
return stdout.strip() == "exists"
|
||
|
||
def setup_venv_and_install_requirements(self, project):
|
||
"""Virtual environment oluştur ve requirements'ları kur"""
|
||
try:
|
||
logger.info(f'"{project.folder_name}" projesi için venv oluşturuluyor')
|
||
|
||
# Venv klasörünün varlığını kontrol et
|
||
check_cmd = f'test -d "{project.get_full_path()}/venv" && echo "exists" || echo "not exists"'
|
||
stdout, stderr, status = self.execute_command(check_cmd)
|
||
|
||
if stdout.strip() == "exists":
|
||
logger.info('Mevcut venv kullanılacak')
|
||
else:
|
||
# Venv oluştur
|
||
logger.info('Yeni venv oluşturuluyor')
|
||
venv_cmd = f'cd "{project.get_full_path()}" && python3 -m venv venv'
|
||
stdout, stderr, status = self.execute_command(venv_cmd)
|
||
|
||
if not status:
|
||
logger.error(f'Venv oluşturma hatası: {stderr}')
|
||
return False, f'Venv oluşturulamadı: {stderr}'
|
||
|
||
logger.info('Venv başarıyla oluşturuldu')
|
||
|
||
# pip'i güncelle ve requirements'ları kur
|
||
logger.info('Requirements kuruluyor')
|
||
install_cmd = f'''
|
||
cd "{project.get_full_path()}" && \
|
||
source venv/bin/activate && \
|
||
pip install --upgrade pip && \
|
||
pip install -r req.txt
|
||
'''
|
||
stdout, stderr, status = self.execute_command(install_cmd)
|
||
|
||
if not status:
|
||
logger.error(f'Requirements kurulum hatası: {stderr}')
|
||
return False, f'Requirements kurulamadı: {stderr}'
|
||
|
||
logger.info('Requirements başarıyla kuruldu')
|
||
return True, "Venv oluşturuldu ve requirements kuruldu"
|
||
|
||
except Exception as e:
|
||
logger.exception(f"Venv ve requirements kurulum hatası: {str(e)}")
|
||
return False, str(e)
|
||
|
||
# SSHManager'ın tüm metodları buraya taşınacak...
|
||
# utils.py'daki SSHManager sınıfının tüm içeriğini buraya kopyalayın |