hosting-platform/backend/app/routes/dns.py

294 lines
10 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"""
DNS routes - Yeni akış ile CF hesap seçimi, NS kontrolü, DNS yönetimi
"""
from flask import Blueprint, request, jsonify
from datetime import datetime
from app.models.domain import db, CloudflareAccount, Domain
from app.services.cloudflare_service import CloudflareService
from app.services.nameserver_service import NameserverService
from app.services.auth_service import token_required
import hashlib
dns_bp = Blueprint('dns', __name__, url_prefix='/api/dns')
def select_lb_ip(domain: str, lb_ips: list) -> str:
"""Domain için load balancer IP seç (hash-based)"""
hash_value = int(hashlib.md5(domain.encode()).hexdigest(), 16)
index = hash_value % len(lb_ips)
return lb_ips[index]
@dns_bp.route('/check-nameservers', methods=['POST'])
def check_nameservers():
"""Domain'in nameserver'larını kontrol et"""
try:
data = request.json
domain = data.get('domain')
if not domain:
return jsonify({"error": "domain gerekli"}), 400
# NS kontrolü yap
result = NameserverService.check_cloudflare_nameservers(domain)
return jsonify(result)
except Exception as e:
return jsonify({
"status": "error",
"message": f"NS kontrolü sırasında hata: {str(e)}"
}), 500
@dns_bp.route('/get-ns-instructions', methods=['POST'])
def get_ns_instructions():
"""NS yönlendirme talimatlarını al"""
try:
data = request.json
domain = data.get('domain')
zone_id = data.get('zone_id')
api_token = data.get('api_token')
if not all([domain, zone_id, api_token]):
return jsonify({"error": "domain, zone_id ve api_token gerekli"}), 400
# Mevcut NS'leri al
current_ns = NameserverService.get_current_nameservers(domain)
# Cloudflare zone NS'lerini al
cf_ns = NameserverService.get_cloudflare_zone_nameservers(zone_id, api_token)
if cf_ns["status"] == "error":
return jsonify(cf_ns), 400
return jsonify({
"status": "success",
"domain": domain,
"current_nameservers": current_ns.get("nameservers", []),
"cloudflare_nameservers": cf_ns["nameservers"],
"instructions": [
"1. Domain sağlayıcınızın (GoDaddy, Namecheap, vb.) kontrol paneline giriş yapın",
"2. Domain yönetimi veya DNS ayarları bölümüne gidin",
"3. 'Nameservers' veya 'Name Servers' seçeneğini bulun",
"4. 'Custom Nameservers' veya 'Use custom nameservers' seçeneğini seçin",
f"5. Aşağıdaki Cloudflare nameserver'larını ekleyin:",
*[f" - {ns}" for ns in cf_ns["nameservers"]],
"6. Değişiklikleri kaydedin",
"7. DNS propagation 24-48 saat sürebilir (genellikle 1-2 saat içinde tamamlanır)"
]
})
except Exception as e:
return jsonify({
"status": "error",
"message": f"NS talimatları alınırken hata: {str(e)}"
}), 500
@dns_bp.route('/validate-token', methods=['POST'])
def validate_cf_token():
"""Cloudflare API token doğrula (müşterinin kendi token'ı)"""
try:
data = request.json
domain = data.get('domain')
cf_token = data.get('cf_token')
if not domain or not cf_token:
return jsonify({"error": "domain ve cf_token gerekli"}), 400
cf_service = CloudflareService(cf_token)
result = cf_service.validate_token_and_get_zone(domain)
return jsonify(result)
except Exception as e:
return jsonify({
"status": "error",
"message": f"Token doğrulama hatası: {str(e)}"
}), 500
@dns_bp.route('/select-company-account', methods=['POST'])
def select_company_account():
"""Şirket CF hesabı seç ve zone oluştur/bul"""
try:
data = request.json
domain = data.get('domain')
cf_account_id = data.get('cf_account_id')
if not domain or not cf_account_id:
return jsonify({"error": "domain ve cf_account_id gerekli"}), 400
# CF hesabını al
cf_account = CloudflareAccount.query.get(cf_account_id)
if not cf_account or not cf_account.is_active:
return jsonify({
"status": "error",
"message": "Cloudflare hesabı bulunamadı veya aktif değil"
}), 404
# Hesap kapasitesi kontrolü
if cf_account.current_domain_count >= cf_account.max_domains:
return jsonify({
"status": "error",
"message": f"Bu hesap kapasitesi dolmuş ({cf_account.current_domain_count}/{cf_account.max_domains})"
}), 400
# API token'ı al
api_token = cf_account.get_api_token()
# Cloudflare'de zone var mı kontrol et
cf_service = CloudflareService(api_token)
result = cf_service.validate_token_and_get_zone(domain)
if result["status"] == "success":
# Zone zaten var
return jsonify({
"status": "success",
"zone_exists": True,
**result
})
else:
# Zone yok, oluşturulması gerekiyor
# TODO: Zone oluşturma fonksiyonu eklenecek
return jsonify({
"status": "pending",
"zone_exists": False,
"message": "Zone bulunamadı. Cloudflare'de zone oluşturulması gerekiyor.",
"cf_account": cf_account.to_dict(include_token=False)
})
except Exception as e:
return jsonify({
"status": "error",
"message": f"Hesap seçimi sırasında hata: {str(e)}"
}), 500
@dns_bp.route('/preview-changes', methods=['POST'])
@token_required
def preview_changes(current_user):
"""DNS değişiklik önizlemesi"""
try:
customer = current_user.customer
if not customer:
return jsonify({'error': 'Customer profile not found'}), 404
data = request.json
domain = data.get('domain')
zone_id = data.get('zone_id')
cf_token = data.get('cf_token')
lb_ips = data.get('lb_ips', ['176.96.129.77']) # Default server IP
if not all([domain, zone_id, cf_token]):
return jsonify({"error": "domain, zone_id ve cf_token gerekli"}), 400
# Load balancer IP seç
new_ip = select_lb_ip(domain, lb_ips)
cf_service = CloudflareService(cf_token)
preview = cf_service.generate_dns_preview(domain, zone_id, new_ip)
return jsonify(preview)
except Exception as e:
return jsonify({
"status": "error",
"message": f"Preview oluşturma hatası: {str(e)}"
}), 500
@dns_bp.route('/apply-changes', methods=['POST'])
@token_required
def apply_changes(current_user):
"""DNS değişikliklerini uygula ve domain'i kaydet"""
try:
customer = current_user.customer
if not customer:
return jsonify({'error': 'Customer profile not found'}), 404
data = request.json
domain_name = data.get('domain')
zone_id = data.get('zone_id')
cf_token = data.get('cf_token')
preview = data.get('preview')
proxy_enabled = data.get('proxy_enabled', True)
cf_account_id = data.get('cf_account_id')
cf_account_type = data.get('cf_account_type', 'company')
project_name = data.get('project_name')
if not all([domain_name, zone_id, cf_token, preview]):
return jsonify({"error": "Eksik parametreler"}), 400
# Check domain limit
current_count = Domain.query.filter_by(customer_id=customer.id).count()
if current_count >= customer.max_domains:
return jsonify({
'error': f'Domain limit reached ({customer.max_domains})'
}), 403
# Check if domain already exists
existing = Domain.query.filter_by(domain_name=domain_name).first()
if existing:
return jsonify({'error': 'Domain already exists'}), 409
cf_service = CloudflareService(cf_token)
# DNS değişikliklerini uygula
result = cf_service.apply_dns_changes(zone_id, preview, proxy_enabled)
if result["status"] == "success":
# SSL yapılandır
ssl_config = cf_service.configure_ssl(zone_id)
# Domain'i veritabanına kaydet
domain_obj = Domain(
domain_name=domain_name,
customer_id=customer.id,
created_by=current_user.id,
project_name=project_name,
use_cloudflare=True,
cf_account_type=cf_account_type,
cf_account_id=cf_account_id if cf_account_type == 'company' else None,
cf_zone_id=zone_id,
cf_proxy_enabled=proxy_enabled,
lb_ip=preview.get("new_ip"),
status="active",
dns_configured=True,
ssl_configured=len(ssl_config.get("errors", [])) == 0
)
# If using own CF account, save encrypted token
if cf_account_type == 'own':
domain_obj.set_cf_api_token(cf_token)
db.session.add(domain_obj)
# Update CF account domain count if using company account
if cf_account_type == 'company' and cf_account_id:
cf_account = CloudflareAccount.query.get(cf_account_id)
if cf_account:
cf_account.current_domain_count += 1
db.session.commit()
return jsonify({
"status": "success",
"dns_result": result,
"ssl_config": ssl_config,
"domain_id": domain_obj.id,
"domain": domain_obj.to_dict()
}), 201
return jsonify(result), 500
except Exception as e:
db.session.rollback()
return jsonify({
"status": "error",
"message": f"DNS uygulama hatası: {str(e)}"
}), 500