mirror of
https://github.com/usmannasir/cyberpanel.git
synced 2025-11-03 03:45:52 +01:00
Refactor DeployAccount to eliminate code duplication and improve error handling
- Remove duplicate code blocks that handled success and "already deployed" cases - Consolidate deployment logic into single code path - Add validation for backup plan state before deployment - Add specific exception handling for API requests and JSON parsing - Add timeout to API requests (30 seconds) - Change API endpoint from HTTP to HTTPS for security - Improve error messages with actionable guidance - Add comprehensive logging for all error paths - Clarify return status: status=1 only on full success, status=0 on any failure - Add early validation for missing SSH public key - Handle edge case where account is deployed but destination creation fails
This commit is contained in:
@@ -2432,122 +2432,159 @@ class BackupManager:
|
||||
return HttpResponse(json_data)
|
||||
|
||||
def DeployAccount(self, request=None, userID=None, data=None):
|
||||
user = Administrator.objects.get(pk=userID)
|
||||
"""Deploy a One-Click Backup account by creating SFTP credentials on remote server"""
|
||||
try:
|
||||
user = Administrator.objects.get(pk=userID)
|
||||
userID = request.session['userID']
|
||||
currentACL = ACLManager.loadedACL(userID)
|
||||
|
||||
userID = request.session['userID']
|
||||
currentACL = ACLManager.loadedACL(userID)
|
||||
import json
|
||||
# Parse request data
|
||||
try:
|
||||
data = json.loads(request.body)
|
||||
backup_id = data['id']
|
||||
except (json.JSONDecodeError, KeyError) as e:
|
||||
logging.CyberCPLogFileWriter.writeToFile(f"Invalid request data in DeployAccount: {str(e)}")
|
||||
return HttpResponse(json.dumps({
|
||||
'status': 0,
|
||||
'error_message': 'Invalid request format. Missing required field: id'
|
||||
}))
|
||||
|
||||
data = json.loads(request.body)
|
||||
id = data['id']
|
||||
# Get backup plan
|
||||
from IncBackups.models import OneClickBackups
|
||||
try:
|
||||
ocb = OneClickBackups.objects.get(pk=backup_id, owner=user)
|
||||
except OneClickBackups.DoesNotExist:
|
||||
logging.CyberCPLogFileWriter.writeToFile(f"OneClickBackup {backup_id} not found for user {userID} [DeployAccount]")
|
||||
return HttpResponse(json.dumps({
|
||||
'status': 0,
|
||||
'error_message': 'Backup plan not found or you do not have permission to access it.'
|
||||
}))
|
||||
|
||||
from IncBackups.models import OneClickBackups
|
||||
ocb = OneClickBackups.objects.get(pk=id, owner=user)
|
||||
# Check if already deployed
|
||||
if ocb.state == 1:
|
||||
logging.CyberCPLogFileWriter.writeToFile(f"Backup plan {backup_id} already deployed [DeployAccount]")
|
||||
return HttpResponse(json.dumps({
|
||||
'status': 1,
|
||||
'error_message': 'This backup account is already deployed.'
|
||||
}))
|
||||
|
||||
data = {}
|
||||
# Read SSH public key
|
||||
try:
|
||||
ssh_pub_key = ProcessUtilities.outputExecutioner('cat /root/.ssh/cyberpanel.pub').strip()
|
||||
if not ssh_pub_key or ssh_pub_key.startswith('cat:'):
|
||||
raise Exception("Failed to read SSH public key")
|
||||
except Exception as e:
|
||||
logging.CyberCPLogFileWriter.writeToFile(f"Failed to read SSH public key: {str(e)} [DeployAccount]")
|
||||
return HttpResponse(json.dumps({
|
||||
'status': 0,
|
||||
'error_message': 'SSH public key not found. Please ensure One-Click Backup is properly configured.'
|
||||
}))
|
||||
|
||||
####
|
||||
# Prepare API request
|
||||
url = 'https://platform.cyberpersons.com/Billing/CreateSFTPAccount'
|
||||
payload = {
|
||||
'sub': ocb.subscription,
|
||||
'key': ssh_pub_key,
|
||||
'sftpUser': ocb.sftpUser,
|
||||
'serverIP': ACLManager.fetchIP(),
|
||||
'planName': ocb.planName
|
||||
}
|
||||
headers = {'Content-Type': 'application/json'}
|
||||
|
||||
import requests
|
||||
import json
|
||||
# Make API request
|
||||
try:
|
||||
response = requests.post(url, headers=headers, data=json.dumps(payload), timeout=30)
|
||||
except requests.exceptions.RequestException as e:
|
||||
logging.CyberCPLogFileWriter.writeToFile(f"API request failed: {str(e)} [DeployAccount]")
|
||||
return HttpResponse(json.dumps({
|
||||
'status': 0,
|
||||
'error_message': f'Failed to connect to backup platform: {str(e)}'
|
||||
}))
|
||||
|
||||
# Define the URL of the endpoint
|
||||
url = 'http://platform.cyberpersons.com/Billing/CreateSFTPAccount' # Replace with your actual endpoint URL
|
||||
# Handle non-200 responses
|
||||
if response.status_code != 200:
|
||||
logging.CyberCPLogFileWriter.writeToFile(f"API returned status {response.status_code}: {response.text} [DeployAccount]")
|
||||
return HttpResponse(json.dumps({
|
||||
'status': 0,
|
||||
'error_message': f'Backup platform returned error (HTTP {response.status_code}). Please try again later.'
|
||||
}))
|
||||
|
||||
# Define the payload to send in the POST request
|
||||
payload = {
|
||||
'sub': ocb.subscription,
|
||||
'key': ProcessUtilities.outputExecutioner(f'cat /root/.ssh/cyberpanel.pub'),
|
||||
# Replace with the actual SSH public key
|
||||
'sftpUser': ocb.sftpUser,
|
||||
'serverIP': ACLManager.fetchIP(), # Replace with the actual server IP
|
||||
'planName': ocb.planName
|
||||
}
|
||||
# Parse API response
|
||||
try:
|
||||
response_data = response.json()
|
||||
except json.JSONDecodeError:
|
||||
logging.CyberCPLogFileWriter.writeToFile(f"Invalid JSON response from API: {response.text} [DeployAccount]")
|
||||
return HttpResponse(json.dumps({
|
||||
'status': 0,
|
||||
'error_message': 'Received invalid response from backup platform.'
|
||||
}))
|
||||
|
||||
# Convert the payload to JSON format
|
||||
headers = {'Content-Type': 'application/json'}
|
||||
dataRet = json.dumps(payload)
|
||||
# Check if deployment was successful or already deployed
|
||||
api_status = response_data.get('status')
|
||||
api_error = response_data.get('error_message', '')
|
||||
|
||||
# Make the POST request
|
||||
response = requests.post(url, headers=headers, data=dataRet)
|
||||
|
||||
# Handle the response
|
||||
# Handle the response
|
||||
if response.status_code == 200:
|
||||
response_data = response.json()
|
||||
if response_data.get('status') == 1:
|
||||
if api_status == 1 or api_error == "Already deployed.":
|
||||
# Both cases are success - account exists and is ready
|
||||
deployment_status = "created" if api_status == 1 else "already deployed"
|
||||
logging.CyberCPLogFileWriter.writeToFile(f"SFTP account {deployment_status} for {ocb.sftpUser} [DeployAccount]")
|
||||
|
||||
# Update backup plan state
|
||||
ocb.state = 1
|
||||
ocb.save()
|
||||
|
||||
print("SFTP account created successfully.")
|
||||
|
||||
finalDic = {}
|
||||
|
||||
finalDic['IPAddress'] = response_data.get('ipAddress')
|
||||
finalDic['password'] = 'NOT-NEEDED'
|
||||
finalDic['backupSSHPort'] = '22'
|
||||
finalDic['userName'] = ocb.sftpUser
|
||||
finalDic['type'] = 'SFTP'
|
||||
finalDic['path'] = 'cpbackups'
|
||||
finalDic['name'] = ocb.sftpUser
|
||||
|
||||
wm = BackupManager()
|
||||
response_inner = wm.submitDestinationCreation(userID, finalDic)
|
||||
|
||||
response_data_inner = json.loads(response_inner.content.decode('utf-8'))
|
||||
|
||||
# Extract the value of 'status'
|
||||
if response_data_inner.get('status') == 0:
|
||||
data_ret = {'status': 1, 'error_message': response_data_inner.get('error_message')}
|
||||
json_data = json.dumps(data_ret)
|
||||
return HttpResponse(json_data)
|
||||
else:
|
||||
data_ret = {'status': 1,}
|
||||
json_data = json.dumps(data_ret)
|
||||
return HttpResponse(json_data)
|
||||
|
||||
else:
|
||||
|
||||
if response_data.get('error_message') == "Already deployed.":
|
||||
ocb.state = 1
|
||||
ocb.save()
|
||||
|
||||
print("SFTP account created successfully.")
|
||||
|
||||
finalDic = {}
|
||||
|
||||
finalDic['IPAddress'] = response_data.get('ipAddress')
|
||||
finalDic['password'] = 'NOT-NEEDED'
|
||||
finalDic['backupSSHPort'] = '22'
|
||||
finalDic['userName'] = ocb.sftpUser
|
||||
finalDic['type'] = 'SFTP'
|
||||
finalDic['path'] = 'cpbackups'
|
||||
finalDic['name'] = ocb.sftpUser
|
||||
# Create local backup destination
|
||||
finalDic = {
|
||||
'IPAddress': response_data.get('ipAddress'),
|
||||
'password': 'NOT-NEEDED',
|
||||
'backupSSHPort': '22',
|
||||
'userName': ocb.sftpUser,
|
||||
'type': 'SFTP',
|
||||
'path': 'cpbackups',
|
||||
'name': ocb.sftpUser
|
||||
}
|
||||
|
||||
try:
|
||||
wm = BackupManager()
|
||||
response_inner = wm.submitDestinationCreation(userID, finalDic)
|
||||
|
||||
response_data_inner = json.loads(response_inner.content.decode('utf-8'))
|
||||
|
||||
# Extract the value of 'status'
|
||||
if response_data_inner.get('status') == 0:
|
||||
data_ret = {'status': 1, 'error_message': response_data_inner.get('error_message')}
|
||||
json_data = json.dumps(data_ret)
|
||||
return HttpResponse(json_data)
|
||||
else:
|
||||
data_ret = {'status': 1, }
|
||||
json_data = json.dumps(data_ret)
|
||||
return HttpResponse(json_data)
|
||||
# Destination creation failed, but account is deployed
|
||||
logging.CyberCPLogFileWriter.writeToFile(
|
||||
f"Destination creation failed: {response_data_inner.get('error_message')} [DeployAccount]"
|
||||
)
|
||||
return HttpResponse(json.dumps({
|
||||
'status': 0,
|
||||
'error_message': f"Account deployed but failed to create local destination: {response_data_inner.get('error_message')}"
|
||||
}))
|
||||
|
||||
data_ret = {'status': 0, 'error_message': response_data.get('error_message')}
|
||||
json_data = json.dumps(data_ret)
|
||||
return HttpResponse(json_data)
|
||||
else:
|
||||
data['message'] = f"[1991] Failed to create sftp account {response.text}"
|
||||
data_ret = {'status': 0, 'error_message': response.text}
|
||||
json_data = json.dumps(data_ret)
|
||||
return HttpResponse(json_data)
|
||||
# Full success
|
||||
return HttpResponse(json.dumps({
|
||||
'status': 1,
|
||||
'message': f'Backup account {deployment_status} successfully.'
|
||||
}))
|
||||
|
||||
except Exception as e:
|
||||
logging.CyberCPLogFileWriter.writeToFile(f"Failed to create destination: {str(e)} [DeployAccount]")
|
||||
return HttpResponse(json.dumps({
|
||||
'status': 0,
|
||||
'error_message': f'Account deployed but failed to create local destination: {str(e)}'
|
||||
}))
|
||||
|
||||
else:
|
||||
# API returned an error
|
||||
logging.CyberCPLogFileWriter.writeToFile(f"API returned error: {api_error} [DeployAccount]")
|
||||
return HttpResponse(json.dumps({
|
||||
'status': 0,
|
||||
'error_message': api_error or 'Unknown error occurred during deployment.'
|
||||
}))
|
||||
|
||||
except Exception as e:
|
||||
logging.CyberCPLogFileWriter.writeToFile(f"Unexpected error in DeployAccount: {str(e)}")
|
||||
return HttpResponse(json.dumps({
|
||||
'status': 0,
|
||||
'error_message': f'An unexpected error occurred: {str(e)}'
|
||||
}))
|
||||
|
||||
def ReconfigureSubscription(self, request=None, userID=None, data=None):
|
||||
try:
|
||||
|
||||
Reference in New Issue
Block a user