finish adding schedules from ui

This commit is contained in:
usman@cyberpersons.com
2023-04-06 23:26:41 +05:00
parent e803e3b9d2
commit 8543a9db5d
9 changed files with 877 additions and 86 deletions

View File

@@ -1299,6 +1299,7 @@ app.controller('restorev2backupoage', function ($scope, $http, $timeout, $compil
}
function getCreationStatus() {
url = "/IncrementalBackups/CreateV2BackupStatus";
@@ -1377,6 +1378,7 @@ app.controller('restorev2backupoage', function ($scope, $http, $timeout, $compil
}
$scope.RestorePathV2 = function (SnapshotId, Path) {
SnapshotId = document.getElementById('Snapshot_id').innerText
@@ -1859,3 +1861,376 @@ function listpaths(pathid, button) {
}
}
app.controller('ScheduleV2Backup', function ($scope, $http, $timeout, $compile) {
$scope.backupLoading = true;
$scope.installationProgress = true;
$scope.errorMessageBox = true;
$scope.success = true;
$scope.couldNotConnect = true;
$scope.goBackDisable = true;
var repoG, frequencyG, websiteDataG, websiteDatabasesG, websiteEmailsG;
$scope.deleteBackupInitialv2 = function (repo, frequency, websiteData, websiteDatabases, websiteEmails) {
repoG = repo;
frequencyG = frequency;
websiteDataG = websiteData;
websiteDatabasesG = websiteDatabases;
websiteEmailsG = websiteEmails;
}
$scope.DeleteScheduleV2 = function () {
$scope.backupLoading = false;
// document.getElementById('CreateV2BackupButton').style.display = "block";
var url = "/IncrementalBackups/DeleteScheduleV2";
var data = {
Selectedwebsite: $scope.selwebsite,
repo: repoG,
frequency: frequencyG,
websiteData: websiteDataG,
websiteDatabases: websiteDatabasesG,
websiteEmails: websiteEmailsG
};
//alert( $scope.selwebsite);
var config = {
headers: {
'X-CSRFToken': getCookie('csrftoken')
}
};
$http.post(url, data, config).then(ListInitialDatas, cantLoadInitialDatas);
function ListInitialDatas(response) {
$scope.backupLoading = true;
if (response.data.status === 1) {
$scope.selectwebsite();
new PNotify({
title: 'Success!',
text: 'Successfully deleted.',
type: 'success'
});
} else {
new PNotify({
title: 'Error!',
text: response.data.error_message,
type: 'error'
});
}
}
function cantLoadInitialDatas(response) {
$scope.backupLoading = true;
new PNotify({
title: 'Operation Failed!',
text: 'Could not connect to server, please refresh this page',
type: 'error'
});
}
}
$scope.selectwebsite = function () {
document.getElementById('reposelectbox').innerHTML = "";
$scope.backupLoading = false;
// document.getElementById('CreateV2BackupButton').style.display = "block";
var url = "/IncrementalBackups/selectwebsiteCreatev2";
var data = {
Selectedwebsite: $scope.selwebsite,
Selectedrepo: $('#reposelectbox').val(),
};
//alert( $scope.selwebsite);
var config = {
headers: {
'X-CSRFToken': getCookie('csrftoken')
}
};
$http.post(url, data, config).then(ListInitialDatas, cantLoadInitialDatas);
function ListInitialDatas(response) {
$scope.backupLoading = true;
if (response.data.status === 1) {
const selectBox = document.getElementById('reposelectbox');
const options = response.data.data;
const option = document.createElement('option');
$scope.records = response.data.currentSchedules;
option.value = 1;
option.text = 'Choose Repo';
selectBox.appendChild(option);
if (options.length >= 1) {
for (let i = 0; i < options.length; i++) {
const option = document.createElement('option');
option.value = options[i];
option.text = options[i];
selectBox.appendChild(option);
}
} else {
new PNotify({
title: 'Error!',
text: 'file empty',
type: 'error'
});
}
} else {
new PNotify({
title: 'Error!',
text: response.data.error_message,
type: 'error'
});
}
}
function cantLoadInitialDatas(response) {
$scope.backupLoading = true;
new PNotify({
title: 'Operation Failed!',
text: 'Could not connect to server, please refresh this page',
type: 'error'
});
}
}
$scope.CreateScheduleV2 = function () {
$scope.backupLoading = false;
// document.getElementById('CreateV2BackupButton').style.display = "block";
var url = "/IncrementalBackups/CreateScheduleV2";
var data = {
Selectedwebsite: $scope.selwebsite,
repo: $('#reposelectbox').val(),
frequency: $scope.frequency,
websiteData: $scope.websiteData,
websiteDatabases: $scope.websiteDatabases,
websiteEmails: $scope.websiteEmails
};
//alert( $scope.selwebsite);
var config = {
headers: {
'X-CSRFToken': getCookie('csrftoken')
}
};
$http.post(url, data, config).then(ListInitialDatas, cantLoadInitialDatas);
function ListInitialDatas(response) {
$scope.backupLoading = true;
if (response.data.status === 1) {
$scope.selectwebsite();
new PNotify({
title: 'Success!',
text: 'Successfully created.',
type: 'success'
});
} else {
new PNotify({
title: 'Error!',
text: response.data.error_message,
type: 'error'
});
}
}
function cantLoadInitialDatas(response) {
$scope.backupLoading = true;
new PNotify({
title: 'Operation Failed!',
text: 'Could not connect to server, please refresh this page',
type: 'error'
});
}
}
var Domain;
$scope.CreateV2BackupButton = function () {
$scope.backupLoading = false;
$scope.installationDetailsForm = true;
$scope.installationProgress = false;
$scope.errorMessageBox = true;
$scope.success = true;
$scope.couldNotConnect = true;
$scope.goBackDisable = true;
var url = "/IncrementalBackups/CreateV2BackupButton";
var websiteData = $scope.websiteData;
var websiteEmails = $scope.websiteEmails;
var websiteDatabases = $scope.websiteDatabases;
var chk = 0;
if (websiteData === true || websiteDatabases === true || websiteEmails === true) {
chk = 1;
}
var data = {};
data = {
Selectedwebsite: $scope.selwebsite,
Selectedrepo: $('#reposelectbox').val(),
websiteDatabases: websiteDatabases,
websiteEmails: websiteEmails,
websiteData: websiteData,
};
var config = {
headers: {
'X-CSRFToken': getCookie('csrftoken')
}
};
//alert('Done..........')
if (chk === 1) {
$http.post(url, data, config).then(ListInitialDatas, cantLoadInitialDatas);
} else {
$scope.backupLoading = true;
new PNotify({
title: 'Choose Backup Content!',
text: 'Please Choose Backup content Data, Database, Email',
type: 'error'
});
}
function ListInitialDatas(response) {
$scope.backupLoading = true;
if (response.data.status === 1) {
Domain = $scope.selwebsite;
getCreationStatus();
} else {
$scope.backupLoading = true;
$scope.installationDetailsForm = true;
$scope.installationProgress = false;
$scope.errorMessageBox = false;
$scope.success = true;
$scope.couldNotConnect = true;
$scope.goBackDisable = false;
$scope.errorMessage = response.data.error_message;
}
}
function cantLoadInitialDatas(response) {
$scope.backupLoading = true;
new PNotify({
title: 'Operation Failed!',
text: 'Could not connect to server, please refresh this page',
type: 'error'
});
}
}
function getCreationStatus() {
url = "/IncrementalBackups/CreateV2BackupStatus";
var data = {
domain: Domain
};
var config = {
headers: {
'X-CSRFToken': getCookie('csrftoken')
}
};
$http.post(url, data, config).then(ListInitialDatas, cantLoadInitialDatas);
function ListInitialDatas(response) {
if (response.data.abort === 1) {
if (response.data.installStatus === 1) {
$scope.webSiteCreationLoading = true;
$scope.installationDetailsForm = true;
$scope.installationProgress = false;
$scope.errorMessageBox = true;
$scope.success = false;
$scope.couldNotConnect = true;
$scope.goBackDisable = false;
$("#installProgress").css("width", "100%");
$scope.installPercentage = "100";
$scope.currentStatus = response.data.currentStatus;
$timeout.cancel();
} else {
$scope.webSiteCreationLoading = true;
$scope.installationDetailsForm = true;
$scope.installationProgress = false;
$scope.errorMessageBox = false;
$scope.success = true;
$scope.couldNotConnect = true;
$scope.goBackDisable = false;
$scope.errorMessage = response.data.error_message;
$("#installProgress").css("width", "0%");
$scope.installPercentage = "0";
$scope.goBackDisable = false;
}
} else {
$scope.webSiteCreationLoading = false;
$("#installProgress").css("width", response.data.installationProgress + "%");
$scope.installPercentage = response.data.installationProgress;
$scope.currentStatus = response.data.currentStatus;
$timeout(getCreationStatus, 1000);
}
}
function cantLoadInitialDatas(response) {
$scope.webSiteCreationLoading = true;
$scope.installationDetailsForm = true;
$scope.installationProgress = false;
$scope.errorMessageBox = true;
$scope.success = true;
$scope.couldNotConnect = false;
$scope.goBackDisable = false;
}
}
});

View File

@@ -0,0 +1,203 @@
{% extends "baseTemplate/index.html" %}
{% load i18n %}
{% block title %}{% trans "Schedule v2 Backup" %}{% endblock %}
{% block content %}
{% load static %}
{% get_current_language as LANGUAGE_CODE %}
<!-- Current language: {{ LANGUAGE_CODE }} -->
<style>
</style>
<div class="container">
<div id="page-title">
<h2>{% trans "Schedule V2 Backup" %} - <a target="_blank" href="http://go.cyberpanel.net/backup"
style="height: 23px;line-height: 21px;"
class="btn btn-border btn-alt border-red btn-link font-red"
title=""><span>{% trans "Backup Docs" %}</span></a></h2>
<p>{% trans "This page can be used to schedule your backups." %}</p>
</div>
<div ng-controller="ScheduleV2Backup" class="panel">
<div class="panel-body">
<h3 class="title-hero">
{% trans "Schedule v2 Backup" %} <img ng-hide="backupLoading"
src="{% static 'images/loading.gif' %}">
</h3>
<div class="example-box-wrapper">
<form class="form-horizontal bordered-row">
<div class="form-group">
<label class="col-sm-3 control-label">{% trans "Select Website" %} </label>
<div class="col-sm-6">
<select id="create-backup-select" ng-change="selectwebsite()" ng-model="selwebsite"
class="form-control">
{% for items in websiteList %}
<option value="{{ items }}">{{ items }}</option>
{% endfor %}
</select>
</div>
</div>
<div class="form-group">
<label class="col-sm-3 control-label">{% trans "Select Website" %} </label>
<div class="col-sm-6">
<select id="create-backup-select" ng-model="frequency"
class="form-control">
<option>30 Minutes</option>
<option>1 Hour</option>
<option>6 Hours</option>
<option>12 Hours</option>
<option>1 Day</option>
<option>3 Days</option>
<option>1 Week</option>
</select>
</div>
</div>
<div class="form-group">
<label class="col-sm-3 control-label">{% trans "Select Repo" %} </label>
<div class="col-sm-6">
<select id="reposelectbox" ng-change="selectrepo()" ng-model="testhabbi"
class="form-control">
</select>
</div>
</div>
<div class="form-group">
<label class="col-sm-3 control-label">{% trans "Backup Content" %}</label>
<div class="col-sm-9">
<div class="checkbox">
<label>
<input ng-model="websiteData" type="checkbox" value="">
Data
</label>
</div>
</div>
<label class="col-sm-3 control-label"></label>
<div class="col-sm-9">
<div class="checkbox">
<label>
<input ng-model="websiteDatabases" type="checkbox" value="">
Databases
</label>
</div>
</div>
<label class="col-sm-3 control-label"></label>
<div class="col-sm-9">
<div class="checkbox">
<label>
<input ng-model="websiteEmails" type="checkbox" value="">
Emails
</label>
</div>
</div>
<!---
<label class="col-sm-3 control-label"></label>
<div class="col-sm-9">
<div class="checkbox">
<label>
<input ng-model="websiteSSLs" type="checkbox" value="">
SSL Certificates
</label>
</div>
</div> -->
</div>
<div class="form-group">
<label class="col-sm-3 control-label">{% trans " " %} </label>
<div class="col-sm-6">
<button class="btn" id="CreateV2BackupButton" ng-click="CreateScheduleV2()"
style="border-radius: 6px;background-color: #3447b7;color: white !important;">
Create Schedule
</button>
</div>
</div>
<!------ List of records --------------->
<div class="form-group">
<div class="col-sm-12">
<table class="table">
<thead>
<tr>
<th>{% trans "Repo" %}</th>
<th>{% trans "Frequency" %}</th>
<th>{% trans "Backup Websites?" %}</th>
<th>{% trans "Backup Databases?" %}</th>
<th>{% trans "Backup Emails?" %}</th>
<th>{% trans "Last Run" %}</th>
<th>{% trans "Delete" %}</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="record in records track by $index">
<td ng-bind="record.repo"></td>
<td ng-bind="record.frequency"></td>
<td ng-bind="record.websiteData"></td>
<td ng-bind="record.websiteDatabases"></td>
<td ng-bind="record.websiteEmails"></td>
<td ng-bind="record.lastRun"></td>
<a data-toggle="modal" href="" data-target="#DeleteScheduleV2">
<td data-toggle="modal" data-target="#DeleteScheduleV2"
ng-click="deleteBackupInitialv2(record.repo, record.frequency, record.websiteData, record.websiteDatabases, record.websiteEmails)">
<img
src="{% static 'images/delete.png' %}"></td>
</a>
<div id="DeleteScheduleV2" class="modal fade" role="dialog">
<div class="modal-dialog">
<!-- Modal content-->
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal">&times;
</button>
<h4 class="modal-title">{% trans "Set up account" %}</h4>
</div>
<div class="modal-body">
<form name="containerSettingsForm" action="/"
class="form-horizontal">
<div ng-hide="installationDetailsForm" class="form-group">
<label class="col-sm-3 control-label">{% trans "Are you sure?" %}</label>
</div>
</form>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-primary"
ng-click="DeleteScheduleV2()">Delete <img
ng-hide="backupLoading"
src="{% static 'images/loading.gif' %}">
</button>
<button type="button"
class="btn btn-default" data-dismiss="modal">
Close
</button>
</div>
</div>
</div>
</div>
</tr>
</tbody>
</table>
</div>
</div>
<!------ List of records --------------->
</form>
</div>
</div>
</div>
</div>
{% endblock %}

View File

@@ -36,4 +36,8 @@ urlpatterns = [
url(r'^CreateV2BackupStatus$', views.CreateV2BackupStatus, name='CreateV2BackupStatus'),
url(r'^ConfigureSftpV2Backup$', views.ConfigureSftpV2Backup, name='ConfigureSftpV2Backup'),
url(r'^schedulev2Backups$', views.schedulev2Backups, name='schedulev2Backups'),
url(r'^DeleteScheduleV2$', views.DeleteScheduleV2, name='DeleteScheduleV2'),
url(r'^CreateScheduleV2$', views.CreateScheduleV2, name='CreateScheduleV2'),
]

View File

@@ -982,6 +982,8 @@ def selectwebsiteCreatev2(request):
command = 'cat %s'%(path)
CurrentContent = pu.outputExecutioner(command)
status, currentSchedules = CPBackupsV2.FetchCurrentSchedules(str(Selectedwebsite))
if CurrentContent.find('No such file or directory') > -1:
LocalRclonePath = f'/home/{obj.domain}/.config/rclone'
@@ -1001,7 +1003,7 @@ def selectwebsiteCreatev2(request):
if result.find('type') > -1:
pattern = r'\[(.*?)\]'
matches = re.findall(pattern, result)
final_json = json.dumps({'status': 1, 'fetchStatus': 1, 'error_message': "None", "data": matches})
final_json = json.dumps({'status': 1, 'fetchStatus': 1, 'error_message': "None", "data": matches, 'currentSchedules': currentSchedules})
return HttpResponse(final_json)
else:
final_json = json.dumps({'status': 0, 'fetchStatus': 0, 'error_message': 'Could not Find repo'})
@@ -1013,10 +1015,10 @@ def selectwebsiteCreatev2(request):
if result.find('type') > -1:
pattern = r'\[(.*?)\]'
matches = re.findall(pattern, result)
final_json = json.dumps({'status': 1, 'fetchStatus': 1, 'error_message': "None", "data": matches})
final_json = json.dumps({'status': 1, 'fetchStatus': 1, 'error_message': "None", "data": matches, 'currentSchedules': currentSchedules})
return HttpResponse(final_json)
else:
final_json = json.dumps({'status': 0, 'fetchStatus': 0, 'error_message': 'Could not Find repo'})
final_json = json.dumps({'status': 0, 'fetchStatus': 0, 'error_message': 'Could not Find repo', 'currentSchedules': currentSchedules})
return HttpResponse(final_json)
@@ -1065,6 +1067,89 @@ def selectreporestorev2(request):
return HttpResponse(final_json)
except BaseException as msg:
final_dic = {'status': 0, 'fetchStatus': 0, 'error_message': str(msg)}
final_json = json.dumps(final_dic)
return HttpResponse(final_json)
def schedulev2Backups(request):
try:
userID = request.session['userID']
bm = BackupManager()
return bm.schedulev2Backups(request, userID)
except KeyError:
return redirect(loadLoginPage)
def DeleteScheduleV2(request):
try:
userID = request.session['userID']
data = json.loads(request.body)
Selectedwebsite = data['Selectedwebsite']
repo = data['repo']
frequency = data['frequency']
websiteData = data['websiteData']
websiteDatabases = data['websiteDatabases']
websiteEmails = data['websiteEmails']
currentACL = ACLManager.loadedACL(userID)
admin = Administrator.objects.get(pk=userID)
if ACLManager.checkOwnership(str(Selectedwebsite), admin, currentACL) == 1:
pass
else:
return ACLManager.loadError()
status, message = CPBackupsV2.DeleteSchedule(Selectedwebsite, repo, frequency, websiteData, websiteDatabases, websiteEmails)
final_dic = {'status': 1, 'error_message': message}
final_json = json.dumps(final_dic)
return HttpResponse(final_json)
# final_json = json.dumps({'status': 1, 'fetchStatus': 1, 'error_message': "None", "data": None})
# return HttpResponse(final_json)
except BaseException as msg:
final_dic = {'status': 0, 'fetchStatus': 0, 'error_message': str(msg)}
final_json = json.dumps(final_dic)
return HttpResponse(final_json)
def CreateScheduleV2(request):
try:
userID = request.session['userID']
data = json.loads(request.body)
Selectedwebsite = data['Selectedwebsite']
repo = data['repo']
frequency = data['frequency']
websiteData = data['websiteData']
websiteDatabases = data['websiteDatabases']
websiteEmails = data['websiteEmails']
#
# extra_args['BackupData'] = data['websiteData'] if 'websiteData' in data else False
# extra_args['BackupEmails'] = data['websiteEmails'] if 'websiteEmails' in data else False
# extra_args['BackupDatabase'] = data['websiteDatabases'] if 'websiteDatabases' in data else False
currentACL = ACLManager.loadedACL(userID)
admin = Administrator.objects.get(pk=userID)
if ACLManager.checkOwnership(str(Selectedwebsite), admin, currentACL) == 1:
pass
else:
return ACLManager.loadError()
status, message = CPBackupsV2.CreateScheduleV2(Selectedwebsite, repo, frequency, websiteData, websiteDatabases, websiteEmails)
final_dic = {'status': 1, 'error_message': message}
final_json = json.dumps(final_dic)
return HttpResponse(final_json)
# final_json = json.dumps({'status': 1, 'fetchStatus': 1, 'error_message': "None", "data": None})
# return HttpResponse(final_json)
except BaseException as msg:
final_dic = {'status': 0, 'fetchStatus': 0, 'error_message': str(msg)}
final_json = json.dumps(final_dic)

View File

@@ -57,12 +57,19 @@ class BackupManager:
websitesName = ACLManager.findAllSites(currentACL, userID)
proc = httpProc(request, 'IncBackups/RestoreV2Backup.html', {'websiteList': websitesName}, 'createBackup')
return proc.render()
def CreateV2backupSite(self, request=None, userID=None, data=None):
currentACL = ACLManager.loadedACL(userID)
websitesName = ACLManager.findAllSites(currentACL, userID)
proc = httpProc(request, 'IncBackups/CreateV2Backup.html', {'websiteList': websitesName}, 'createBackup')
return proc.render()
def schedulev2Backups(self, request=None, userID=None, data=None):
currentACL = ACLManager.loadedACL(userID)
websitesName = ACLManager.findAllSites(currentACL, userID)
proc = httpProc(request, 'IncBackups/ScheduleV2Backup.html', {'websiteList': websitesName}, 'createBackup')
return proc.render()
def gDrive(self, request=None, userID=None, data=None):
currentACL = ACLManager.loadedACL(userID)
admin = Administrator.objects.get(pk=userID)

View File

@@ -31,7 +31,6 @@
data-target="#setupGdrive"><span>{% trans "Setup new Account" %}</span></a>
<div id="setupGdrive" class="modal fade" role="dialog">
<div class="modal-dialog">
<!-- Modal content-->
<div class="modal-content">
<div class="modal-header">

View File

@@ -689,6 +689,9 @@
<li><a href="{% url 'RestoreV2backupSite' %}"
title="{% trans "Restore V2 Backup" %}"><span>{% trans "Restore V2 Backup" %}</span></a>
</li>
<li><a href="{% url 'schedulev2Backups' %}"
title="{% trans "Schedule V2 Backup" %}"><span>{% trans "Schedule V2 Backup" %}</span></a>
</li>
</ul>

View File

@@ -21,6 +21,7 @@ except:
from plogical.processUtilities import ProcessUtilities
import threading as multi
class CPBackupsV2(multi.Thread):
PENDING_START = 0
RUNNING = 1
@@ -106,7 +107,6 @@ class CPBackupsV2(multi.Thread):
except:
CurrentContent = ''
if type == CPBackupsV2.SFTP:
## config = {"name":, "host":, "user":, "port":, "path":, "password":,}
command = f'rclone obscure {config["password"]}'
@@ -130,7 +130,8 @@ pass = {ObsecurePassword}
return HttpResponse(final_json)
elif type == CPBackupsV2.GDrive:
token = """{"access_token":"%s","token_type":"Bearer","refresh_token":"%s"}""" %(config["token"], config["refresh_token"])
token = """{"access_token":"%s","token_type":"Bearer","refresh_token":"%s"}""" % (
config["token"], config["refresh_token"])
content = f'''{CurrentContent}
[{config["name"]}]
@@ -166,14 +167,14 @@ token = {token}
file = open(self.StatusFile, 'a')
file.writelines("[" + time.strftime(
"%m.%d.%Y_%H-%M-%S") + ":FAILED] " + message + "[404]" +"\n")
"%m.%d.%Y_%H-%M-%S") + ":FAILED] " + message + "[404]" + "\n")
file.close()
elif status == CPBackupsV2.COMPLETED:
self.website.BackupLock = 0
self.website.save()
file = open(self.StatusFile, 'a')
file.writelines("[" + time.strftime(
"%m.%d.%Y_%H-%M-%S") + ":COMPLETED] " + message + "[200]" +"\n")
"%m.%d.%Y_%H-%M-%S") + ":COMPLETED] " + message + "[200]" + "\n")
file.close()
else:
file = open(self.StatusFile, 'a')
@@ -191,8 +192,8 @@ token = {token}
command = f'rustic init -r {self.repo} --password ""'
ProcessUtilities.executioner(command, self.website.externalApp)
#command = f'chown cyberpanel:cyberpanel {self.FinalPathRuctic}'
#ProcessUtilities.executioner(command)
# command = f'chown cyberpanel:cyberpanel {self.FinalPathRuctic}'
# ProcessUtilities.executioner(command)
command = f'chown {self.website.externalApp}:{self.website.externalApp} {self.FinalPathRuctic}/config.json'
ProcessUtilities.executioner(command)
@@ -219,8 +220,7 @@ token = {token}
def MergeSnapshots(self):
snapshots = ''
for snapshot in self.snapshots:
snapshots= f'{snapshots} {snapshot}'
snapshots = f'{snapshots} {snapshot}'
command = f'rustic -r {self.repo} merge {snapshots} --password "" --json'
result = ProcessUtilities.outputExecutioner(command, self.website.externalApp, True)
@@ -254,7 +254,7 @@ token = {token}
### Init rustic repo in main func so dont need to do again and again
while(1):
while (1):
self.website = Websites.objects.get(domain=self.data['domain'])
@@ -263,12 +263,15 @@ token = {token}
Disk1 = f"du -sm /home/{self.website.domain}/"
Disk2 = "2>/dev/null | awk '{print $1}'"
self.WebsiteDiskUsage = int(ProcessUtilities.outputExecutioner(f"{Disk1} {Disk2}", 'root', True).rstrip('\n'))
self.WebsiteDiskUsage = int(
ProcessUtilities.outputExecutioner(f"{Disk1} {Disk2}", 'root', True).rstrip('\n'))
self.CurrentFreeSpaceOnDisk = int(ProcessUtilities.outputExecutioner("df -m / | awk 'NR==2 {print $4}'", 'root', True).rstrip('\n'))
self.CurrentFreeSpaceOnDisk = int(
ProcessUtilities.outputExecutioner("df -m / | awk 'NR==2 {print $4}'", 'root', True).rstrip('\n'))
if self.WebsiteDiskUsage > self.CurrentFreeSpaceOnDisk:
self.UpdateStatus(f'Not enough disk space on the server to backup this website.', CPBackupsV2.FAILED)
self.UpdateStatus(f'Not enough disk space on the server to backup this website.',
CPBackupsV2.FAILED)
return 0
### Before doing anything install rustic
@@ -279,30 +282,26 @@ token = {token}
self.UpdateStatus(f'Failed to install Rustic, error: {message}', CPBackupsV2.FAILED)
return 0
# = Backupsv2(website=self.website, fileName='backup-' + self.data['domain'] + "-" + time.strftime("%m.%d.%Y_%H-%M-%S"), status=CPBackupsV2.RUNNING, BasePath=self.data['BasePath'])
#self.buv2.save()
# self.buv2.save()
#self.FinalPath = f"{self.data['BasePath']}/{self.buv2.fileName}"
# self.FinalPath = f"{self.data['BasePath']}/{self.buv2.fileName}"
### Rustic backup final path
self.FinalPathRuctic = f"{self.data['BasePath']}/{self.website.domain}"
# command = f"mkdir -p {self.FinalPath}"
# ProcessUtilities.executioner(command)
#command = f"mkdir -p {self.FinalPath}"
#ProcessUtilities.executioner(command)
# command = f"chown {website.externalApp}:{website.externalApp} {self.FinalPath}"
# ProcessUtilities.executioner(command)
# command = f'chown cyberpanel:cyberpanel {self.FinalPath}'
# ProcessUtilities.executioner(command)
#command = f"chown {website.externalApp}:{website.externalApp} {self.FinalPath}"
#ProcessUtilities.executioner(command)
#command = f'chown cyberpanel:cyberpanel {self.FinalPath}'
#ProcessUtilities.executioner(command)
#command = f"chmod 711 {self.FinalPath}"
#ProcessUtilities.executioner(command)
# command = f"chmod 711 {self.FinalPath}"
# ProcessUtilities.executioner(command)
command = f"mkdir -p {self.FinalPathRuctic}"
ProcessUtilities.executioner(command)
@@ -317,10 +316,14 @@ token = {token}
self.UpdateStatus('Creating backup config,0', CPBackupsV2.RUNNING)
Config = {'MainWebsite': model_to_dict(self.website, fields=['domain', 'adminEmail', 'phpSelection', 'state', 'config'])}
Config['admin'] = model_to_dict(self.website.admin, fields=['userName', 'password', 'firstName', 'lastName',
Config = {'MainWebsite': model_to_dict(self.website,
fields=['domain', 'adminEmail', 'phpSelection', 'state',
'config'])}
Config['admin'] = model_to_dict(self.website.admin,
fields=['userName', 'password', 'firstName', 'lastName',
'email', 'type', 'owner', 'token', 'api', 'securityLevel',
'state', 'initself.websitesLimit', 'twoFA', 'secretKey', 'config'])
'state', 'initself.websitesLimit', 'twoFA', 'secretKey',
'config'])
Config['acl'] = model_to_dict(self.website.admin.acl)
### Child domains to config
@@ -333,7 +336,7 @@ token = {token}
Config['ChildDomains'] = ChildsList
#print(str(Config))
# print(str(Config))
### Databases
@@ -367,7 +370,9 @@ token = {token}
WPSitesList = []
for wpsite in self.website.wpsites_set.all():
WPSitesList.append(model_to_dict(wpsite,fields=['title', 'path', 'FinalURL', 'AutoUpdates', 'PluginUpdates', 'ThemeUpdates', 'WPLockState']))
WPSitesList.append(model_to_dict(wpsite, fields=['title', 'path', 'FinalURL', 'AutoUpdates',
'PluginUpdates', 'ThemeUpdates',
'WPLockState']))
Config['WPSites'] = WPSitesList
self.config = Config
@@ -403,8 +408,8 @@ token = {token}
except:
pass
#command = f"echo '{json.dumps(Config)}' > {self.FinalPath}/config.json"
#ProcessUtilities.executioner(command, self.website.externalApp, True)
# command = f"echo '{json.dumps(Config)}' > {self.FinalPath}/config.json"
# ProcessUtilities.executioner(command, self.website.externalApp, True)
command = f'chown cyberpanel:cyberpanel {self.FinalPathRuctic}/config.json'
ProcessUtilities.executioner(command)
@@ -476,8 +481,8 @@ token = {token}
### excluded databases are in a list self.data['ExcludedDatabases'] only backup databases if backupdatabase check is on
## For example if self.data['BackupDatabase'] is one then only run this function otherwise not
#command = f'chown {self.website.externalApp}:{self.website.externalApp} {self.FinalPathRuctic}'
#ProcessUtilities.executioner(command)
# command = f'chown {self.website.externalApp}:{self.website.externalApp} {self.FinalPathRuctic}'
# ProcessUtilities.executioner(command)
command = f'rustic init -r {self.repo} --password ""'
ProcessUtilities.executioner(command, self.website.externalApp)
@@ -496,19 +501,19 @@ token = {token}
CurrentDBPath = f"{self.FinalPathRuctic}/{key}.sql"
DBResult, SnapID = mysqlUtilities.createDatabaseBackup(key, self.FinalPathRuctic, 1, self.repo, self.website.externalApp)
DBResult, SnapID = mysqlUtilities.createDatabaseBackup(key, self.FinalPathRuctic, 1, self.repo,
self.website.externalApp)
if DBResult == 1:
self.snapshots.append(SnapID)
#command = f'chown {self.website.externalApp}:{self.website.externalApp} {CurrentDBPath}'
#ProcessUtilities.executioner(command)
# command = f'chown {self.website.externalApp}:{self.website.externalApp} {CurrentDBPath}'
# ProcessUtilities.executioner(command)
## Now pack config into same thing
#command = f'chown {self.website.externalApp}:{self.website.externalApp} {self.FinalPathRuctic}/config.json'
#ProcessUtilities.executioner(command)
# command = f'chown {self.website.externalApp}:{self.website.externalApp} {self.FinalPathRuctic}/config.json'
# ProcessUtilities.executioner(command)
# command = f'rustic -r {self.repo} backup {CurrentDBPath} --password "" --json 2>/dev/null'
# print(f'db command rustic: {command}')
@@ -555,16 +560,16 @@ token = {token}
### excluded directories are in a list self.data['ExcludedDirectories'] only backup data if backupdata check is on
## For example if self.data['BackupData'] is one then only run this function otherwise not
#command = f'chown {self.website.externalApp}:{self.website.externalApp} {self.FinalPathRuctic}'
#ProcessUtilities.executioner(command)
# command = f'chown {self.website.externalApp}:{self.website.externalApp} {self.FinalPathRuctic}'
# ProcessUtilities.executioner(command)
command = f'rustic init -r {self.repo} --password ""'
ProcessUtilities.executioner(command, self.website.externalApp)
source = f'/home/{self.website.domain}'
#command = f'chown {self.website.externalApp}:{self.website.externalApp} {self.FinalPathRuctic}/config.json'
#ProcessUtilities.executioner(command)
# command = f'chown {self.website.externalApp}:{self.website.externalApp} {self.FinalPathRuctic}/config.json'
# ProcessUtilities.executioner(command)
## Pending add user provided folders in the exclude list
@@ -573,7 +578,6 @@ token = {token}
command = f'rustic -r {self.repo} backup {source} --password "" {exclude} --json 2>/dev/null'
result = json.loads(ProcessUtilities.outputExecutioner(command, self.website.externalApp, True).rstrip('\n'))
try:
SnapShotID = result['id'] ## snapshot id that we need to store in db
files_new = result['summary']['files_new'] ## basically new files in backup
@@ -583,13 +587,13 @@ token = {token}
### Config is saved with each backup, snapshot of config is attached to data snapshot with parent
#self.BackupConfig(SnapShotID)
# self.BackupConfig(SnapShotID)
except BaseException as msg:
self.UpdateStatus(f'Backup failed as no snapshot id found, error: {str(msg)}', CPBackupsV2.FAILED)
return 0
#self.UpdateStatus(f'Rustic command result id: {SnapShotID}, files new {files_new}, total_duration {total_duration}', CPBackupsV2.RUNNING)
# self.UpdateStatus(f'Rustic command result id: {SnapShotID}, files new {files_new}, total_duration {total_duration}', CPBackupsV2.RUNNING)
return 1
@@ -599,15 +603,14 @@ token = {token}
### excluded emails are in a list self.data['ExcludedEmails'] only backup data if backupemail check is on
## For example if self.data['BackupEmails'] is one then only run this function otherwise not
#command = f'chown {self.website.externalApp}:{self.website.externalApp} {self.FinalPathRuctic}'
#ProcessUtilities.executioner(command)
# command = f'chown {self.website.externalApp}:{self.website.externalApp} {self.FinalPathRuctic}'
# ProcessUtilities.executioner(command)
command = f'rustic init -r {self.repo} --password ""'
ProcessUtilities.executioner(command, self.website.externalApp)
#command = f'chown {self.website.externalApp}:{self.website.externalApp} {self.FinalPathRuctic}/config.json'
#ProcessUtilities.executioner(command)
# command = f'chown {self.website.externalApp}:{self.website.externalApp} {self.FinalPathRuctic}/config.json'
# ProcessUtilities.executioner(command)
source = f'/home/vmail/{self.website.domain}'
@@ -628,7 +631,7 @@ token = {token}
### Config is saved with each email backup, snapshot of config is attached to email snapshot with parent
#self.BackupConfig(SnapShotID)
# self.BackupConfig(SnapShotID)
except BaseException as msg:
self.UpdateStatus(f'Backup failed as no snapshot id found, error: {str(msg)}', CPBackupsV2.FAILED)
@@ -643,7 +646,7 @@ token = {token}
### if restore then status file should be restore status file
self.restore = 1
#self.StatusFile = self.StatusFile_Restore
# self.StatusFile = self.StatusFile_Restore
from websiteFunctions.models import Websites
from plogical.mysqlUtilities import mysqlUtilities
@@ -664,7 +667,7 @@ token = {token}
### Init rustic repo in main func so dont need to do again and again
while(1):
while (1):
self.website = Websites.objects.get(domain=self.data['domain'])
@@ -673,19 +676,21 @@ token = {token}
Disk1 = f"du -sm /home/{self.website.domain}/"
Disk2 = "2>/dev/null | awk '{print $1}'"
self.WebsiteDiskUsage = int(ProcessUtilities.outputExecutioner(f"{Disk1} {Disk2}", 'root', True).rstrip('\n'))
self.WebsiteDiskUsage = int(
ProcessUtilities.outputExecutioner(f"{Disk1} {Disk2}", 'root', True).rstrip('\n'))
self.CurrentFreeSpaceOnDisk = int(ProcessUtilities.outputExecutioner("df -m / | awk 'NR==2 {print $4}'", 'root', True).rstrip('\n'))
self.CurrentFreeSpaceOnDisk = int(
ProcessUtilities.outputExecutioner("df -m / | awk 'NR==2 {print $4}'", 'root', True).rstrip('\n'))
if self.WebsiteDiskUsage > self.CurrentFreeSpaceOnDisk:
self.UpdateStatus(f'Not enough disk space on the server to restore this website.', CPBackupsV2.FAILED)
self.UpdateStatus(f'Not enough disk space on the server to restore this website.',
CPBackupsV2.FAILED)
return 0
### Rustic backup final path
self.FinalPathRuctic = f"{self.data['BasePath']}/{self.website.domain}"
command = f"mkdir -p {self.FinalPathRuctic}"
ProcessUtilities.executioner(command)
@@ -698,7 +703,8 @@ token = {token}
### Find Restore path first, if path is db, only then restore it to cp
if self.data["path"].find('.sql') > -1:
mysqlUtilities.restoreDatabaseBackup(self.data["path"].rstrip('.sql'), None, None, None, None, 1, self.repo, self.website.externalApp, self.data["snapshotid"])
mysqlUtilities.restoreDatabaseBackup(self.data["path"].rstrip('.sql'), None, None, None, None, 1,
self.repo, self.website.externalApp, self.data["snapshotid"])
else:
if self.data["path"].find('/home/vmail') > -1:
@@ -736,10 +742,118 @@ token = {token}
from websiteFunctions.models import Websites
self.website = Websites.objects.get(domain=self.data['domain'])
command = f'rustic -r {self.repo} forget {deleteString} --prune --password "" 2>/dev/null'
result = ProcessUtilities.outputExecutioner(command, None, True)
@staticmethod
def FetchCurrentSchedules(website):
try:
finalConfigPath = f'/home/cyberpanel/v2backups/{website}'
if os.path.exists(finalConfigPath):
command = f'cat {finalConfigPath}'
RetResult = ProcessUtilities.outputExecutioner(command)
print(repr(RetResult))
BackupConfig = json.loads(ProcessUtilities.outputExecutioner(command).rstrip('\n'))
schedules = []
for value in BackupConfig['schedules']:
schedules.append({'repo': value['repo'], 'frequency': value['frequency'], 'websiteData': value['websiteData'],
'websiteEmails': value['websiteEmails'],
'websiteDatabases': value['websiteDatabases'], 'lastRun': value['lastRun'],
'domain': website})
return 1, schedules
else:
return 1, []
except BaseException as msg:
return 0, str(msg)
@staticmethod
def DeleteSchedule(website, repo, frequency, websiteData, websiteDatabases, websiteEmails):
try:
finalConfigPath = f'/home/cyberpanel/v2backups/{website}'
if os.path.exists(finalConfigPath):
command = f'cat {finalConfigPath}'
RetResult = ProcessUtilities.outputExecutioner(command)
print(repr(RetResult))
BackupConfig = json.loads(ProcessUtilities.outputExecutioner(command).rstrip('\n'))
counter = 0
for value in BackupConfig['schedules']:
if value['repo'] == repo and value['frequency'] == frequency and value['websiteData'] == websiteData and \
value['websiteEmails'] == websiteEmails and value['websiteDatabases'] == websiteDatabases:
del BackupConfig['schedules'][counter]
break
else:
counter = counter + 1
FinalContent = json.dumps(BackupConfig)
WriteToFile = open(finalConfigPath, 'w')
WriteToFile.write(FinalContent)
WriteToFile.close()
return 1, BackupConfig
else:
return 1, []
except BaseException as msg:
return 0, str(msg)
@staticmethod
def CreateScheduleV2(website, repo, frequency, websiteData, websiteDatabases, websiteEmails):
try:
finalConfigPath = f'/home/cyberpanel/v2backups/{website}'
if os.path.exists(finalConfigPath):
logging.CyberCPLogFileWriter.writeToFile('22222')
command = f'cat {finalConfigPath}'
RetResult = ProcessUtilities.outputExecutioner(command)
print(repr(RetResult))
BackupConfig = json.loads(ProcessUtilities.outputExecutioner(command).rstrip('\n'))
try:
BackupConfig['schedules'].append({"repo": repo, "retention": "7", "frequency": frequency, "websiteData": websiteData,
"websiteEmails": websiteEmails, "websiteDatabases": websiteDatabases,
"lastRun": ""})
except:
BackupConfig['schedules'] = [{"repo": repo, "retention": "7", "frequency": frequency, "websiteData": websiteData,
"websiteEmails": websiteEmails, "websiteDatabases": websiteDatabases,
"lastRun": ""}]
# BackupConfig['schedules'] = {"retention": "7", "frequency": frequency, "websiteData": websiteData,
# "websiteEmails": websiteEmails, "websiteDatabases": websiteDatabases,
# "lastRun": ""}
FinalContent = json.dumps(BackupConfig)
WriteToFile = open(finalConfigPath, 'w')
WriteToFile.write(FinalContent)
WriteToFile.close()
return 1, BackupConfig
else:
BackupConfig = {'site': website,
'schedules':
[{"repo": repo, "retention": "7", "frequency": frequency,
"websiteData": websiteData,
"websiteEmails": websiteEmails, "websiteDatabases": websiteDatabases,
"lastRun": ""}]}
FinalContent = json.dumps(BackupConfig)
WriteToFile = open(finalConfigPath, 'w')
WriteToFile.write(FinalContent)
WriteToFile.close()
return 1, BackupConfig
except BaseException as msg:
return 0, str(msg)
# def BackupEmails(self):
#
# ### This function will backup emails of the website, also need to take care of emails that we need to exclude
@@ -840,11 +954,13 @@ token = {token}
else:
return 0, str(response.content)
#sudo mv filename /usr/bin/
command = 'wget -P /home/rustic https://github.com/rustic-rs/rustic/releases/download/%s/rustic-%s-x86_64-unknown-linux-musl.tar.gz' %(version, version)
# sudo mv filename /usr/bin/
command = 'wget -P /home/rustic https://github.com/rustic-rs/rustic/releases/download/%s/rustic-%s-x86_64-unknown-linux-musl.tar.gz' % (
version, version)
ProcessUtilities.executioner(command)
command = 'tar xzf /home/rustic/rustic-%s-x86_64-unknown-linux-musl.tar.gz -C /home/rustic//'%(version)
command = 'tar xzf /home/rustic/rustic-%s-x86_64-unknown-linux-musl.tar.gz -C /home/rustic//' % (
version)
ProcessUtilities.executioner(command)
command = 'sudo mv /home/rustic/rustic /usr/bin/'
@@ -858,11 +974,10 @@ token = {token}
except BaseException as msg:
print('Error: %s'%msg)
print('Error: %s' % msg)
return 0, str(msg)
if __name__ == "__main__":
try:
parser = argparse.ArgumentParser(description='CyberPanel Backup Generator')
@@ -873,8 +988,10 @@ if __name__ == "__main__":
if args.function == "BackupDataBases":
cpbuv2 = CPBackupsV2({'finalPath': args.path})
#cpbuv2.BackupDataBases()
# cpbuv2.BackupDataBases()
except:
cpbuv2 = CPBackupsV2({'function':'InitiateRestore', 'domain': 'cyberpanel.net', 'BasePath': '/home/backup', 'SnapShotID': 1, 'BackendName': 'usman'} )
cpbuv2 = CPBackupsV2(
{'function': 'InitiateRestore', 'domain': 'cyberpanel.net', 'BasePath': '/home/backup', 'SnapShotID': 1,
'BackendName': 'usman'})
cpbuv2.InitiateRestore()

View File

@@ -1411,18 +1411,16 @@ Automatic backup failed for %s on %s.
print(repr(RetResult))
BackupConfig = json.loads(ProcessUtilities.outputExecutioner(command).rstrip('\n'))
for key, value in BackupConfig.items():
for value in BackupConfig['schedules']:
try:
print(key, '->', value)
if key == 'site':
continue
if value['frequency'] == function:
extra_args = {}
extra_args['function'] = 'InitiateBackup'
extra_args['website'] = website.domain
extra_args['domain'] = website.domain
extra_args['BasePath'] = '/home/backup'
extra_args['BackendName'] = key
extra_args['BackendName'] = value['repo']
extra_args['BackupData'] = value['websiteData'] if 'websiteData' in value else False
extra_args['BackupEmails'] = value['websiteEmails'] if 'websiteEmails' in value else False
extra_args['BackupDatabase'] = value['websiteDatabases'] if 'websiteDatabases' in value else False
@@ -1450,7 +1448,7 @@ Automatic Backupv2 failed for %s on %s.
logging.SendEmail(sender, TO, message)
else:
BackupConfig[key]['lastRun'] = time.strftime("%m.%d.%Y_%H-%M-%S")
value['lastRun'] = time.strftime("%m.%d.%Y_%H-%M-%S")
except BaseException as msg:
print("Error: [v2Backups]: %s" % str(msg))
logging.writeToFile('%s. [v2Backups]' % (str(msg)))