feat: add batch backup templates and update UI for multi-VM job processing
This commit is contained in:
parent
85ca39f0ff
commit
9e5f6bfa24
43
gui_app.py
43
gui_app.py
@ -1179,7 +1179,7 @@ def job_to_display(jid, info):
|
|||||||
'started_fmt': fmt_time(info.get('started')),
|
'started_fmt': fmt_time(info.get('started')),
|
||||||
'dest': info.get('dest', ''),
|
'dest': info.get('dest', ''),
|
||||||
'run_dest': info.get('run_dest', ''),
|
'run_dest': info.get('run_dest', ''),
|
||||||
'replication_dest': info.get('replication_dest', ''),
|
'replication_dest': info.get('replication_dest') or '',
|
||||||
'compress': info.get('compress', False),
|
'compress': info.get('compress', False),
|
||||||
'sftp_host': info.get('sftp_host', ''),
|
'sftp_host': info.get('sftp_host', ''),
|
||||||
'schedule_type': info.get('schedule_type', 'now'),
|
'schedule_type': info.get('schedule_type', 'now'),
|
||||||
@ -1439,7 +1439,7 @@ def run_job_thread_impl(jid):
|
|||||||
|
|
||||||
# Replicate successful backup if replication_dest is configured
|
# Replicate successful backup if replication_dest is configured
|
||||||
rep_dest = info.get('replication_dest')
|
rep_dest = info.get('replication_dest')
|
||||||
if rep_dest:
|
if rep_dest and str(rep_dest).strip() and str(rep_dest).strip().lower() != 'none':
|
||||||
rep_vm_dest = os.path.join(rep_dest, vm, f"backup-{run_timestamp}")
|
rep_vm_dest = os.path.join(rep_dest, vm, f"backup-{run_timestamp}")
|
||||||
replicate_backup_folder(vm_dest, rep_vm_dest, log_path=log_path)
|
replicate_backup_folder(vm_dest, rep_vm_dest, log_path=log_path)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
@ -1467,10 +1467,11 @@ def run_job_thread_impl(jid):
|
|||||||
enforce_retention_policy(vm_info, log_path=log_path)
|
enforce_retention_policy(vm_info, log_path=log_path)
|
||||||
|
|
||||||
# Enforce retention policy on replication target if configured
|
# Enforce retention policy on replication target if configured
|
||||||
if info.get('replication_dest'):
|
rep_dest = info.get('replication_dest')
|
||||||
|
if rep_dest and str(rep_dest).strip() and str(rep_dest).strip().lower() != 'none':
|
||||||
rep_vm_info = {
|
rep_vm_info = {
|
||||||
'vm_name': vm,
|
'vm_name': vm,
|
||||||
'dest': info['replication_dest'],
|
'dest': rep_dest,
|
||||||
'retention_type': info.get('retention_type', 'keep_all'),
|
'retention_type': info.get('retention_type', 'keep_all'),
|
||||||
'retention_value': info.get('retention_value', 5)
|
'retention_value': info.get('retention_value', 5)
|
||||||
}
|
}
|
||||||
@ -1536,7 +1537,7 @@ def run_job_thread_impl(jid):
|
|||||||
|
|
||||||
# Replicate successful backup if replication_dest is configured
|
# Replicate successful backup if replication_dest is configured
|
||||||
rep_dest = info.get('replication_dest')
|
rep_dest = info.get('replication_dest')
|
||||||
if rep_dest:
|
if rep_dest and str(rep_dest).strip() and str(rep_dest).strip().lower() != 'none':
|
||||||
rep_run_dest = os.path.join(rep_dest, info['vm_name'], f"backup-{run_timestamp}")
|
rep_run_dest = os.path.join(rep_dest, info['vm_name'], f"backup-{run_timestamp}")
|
||||||
replicate_backup_folder(run_dest, rep_run_dest, log_path=log_path)
|
replicate_backup_folder(run_dest, rep_run_dest, log_path=log_path)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
@ -1552,10 +1553,11 @@ def run_job_thread_impl(jid):
|
|||||||
enforce_retention_policy(info, log_path=log_path)
|
enforce_retention_policy(info, log_path=log_path)
|
||||||
|
|
||||||
# Enforce retention policy on replication target if configured
|
# Enforce retention policy on replication target if configured
|
||||||
if info.get('replication_dest'):
|
rep_dest = info.get('replication_dest')
|
||||||
|
if rep_dest and str(rep_dest).strip() and str(rep_dest).strip().lower() != 'none':
|
||||||
rep_info = {
|
rep_info = {
|
||||||
'vm_name': info['vm_name'],
|
'vm_name': info['vm_name'],
|
||||||
'dest': info['replication_dest'],
|
'dest': rep_dest,
|
||||||
'retention_type': info.get('retention_type', 'keep_all'),
|
'retention_type': info.get('retention_type', 'keep_all'),
|
||||||
'retention_value': info.get('retention_value', 5)
|
'retention_value': info.get('retention_value', 5)
|
||||||
}
|
}
|
||||||
@ -1879,7 +1881,14 @@ def create_job():
|
|||||||
if request.method == 'POST':
|
if request.method == 'POST':
|
||||||
vm_name = request.form.get('vm_name', '').strip()
|
vm_name = request.form.get('vm_name', '').strip()
|
||||||
dest = request.form.get('dest', './backups').strip()
|
dest = request.form.get('dest', './backups').strip()
|
||||||
replication_dest = request.form.get('replication_dest', '').strip() or None
|
# Check if replication is enabled
|
||||||
|
enable_replication = 'enable_replication' in request.form
|
||||||
|
if enable_replication:
|
||||||
|
replication_dest = request.form.get('replication_dest', '').strip()
|
||||||
|
if not replication_dest or replication_dest.lower() == 'none':
|
||||||
|
replication_dest = None
|
||||||
|
else:
|
||||||
|
replication_dest = None
|
||||||
compress = 'compress' in request.form
|
compress = 'compress' in request.form
|
||||||
no_verify_ssl = 'no_verify_ssl' in request.form
|
no_verify_ssl = 'no_verify_ssl' in request.form
|
||||||
sftp_host = request.form.get('sftp_host', '').strip() or None
|
sftp_host = request.form.get('sftp_host', '').strip() or None
|
||||||
@ -1996,7 +2005,14 @@ def batch_jobs():
|
|||||||
if request.method == 'POST':
|
if request.method == 'POST':
|
||||||
vm_names = request.form.getlist('vms')
|
vm_names = request.form.getlist('vms')
|
||||||
dest = request.form.get('dest', './backups').strip()
|
dest = request.form.get('dest', './backups').strip()
|
||||||
replication_dest = request.form.get('replication_dest', '').strip() or None
|
# Check if replication is enabled
|
||||||
|
enable_replication = 'enable_replication' in request.form
|
||||||
|
if enable_replication:
|
||||||
|
replication_dest = request.form.get('replication_dest', '').strip()
|
||||||
|
if not replication_dest or replication_dest.lower() == 'none':
|
||||||
|
replication_dest = None
|
||||||
|
else:
|
||||||
|
replication_dest = None
|
||||||
compress = 'compress' in request.form
|
compress = 'compress' in request.form
|
||||||
no_verify_ssl = 'no_verify_ssl' in request.form
|
no_verify_ssl = 'no_verify_ssl' in request.form
|
||||||
disk_strategy = request.form.get('disk_strategy', 'all')
|
disk_strategy = request.form.get('disk_strategy', 'all')
|
||||||
@ -2375,7 +2391,14 @@ def edit_job(jobid):
|
|||||||
|
|
||||||
if request.method == 'POST':
|
if request.method == 'POST':
|
||||||
dest = request.form.get('dest', './backups').strip()
|
dest = request.form.get('dest', './backups').strip()
|
||||||
replication_dest = request.form.get('replication_dest', '').strip() or None
|
# Check if replication is enabled
|
||||||
|
enable_replication = 'enable_replication' in request.form
|
||||||
|
if enable_replication:
|
||||||
|
replication_dest = request.form.get('replication_dest', '').strip()
|
||||||
|
if not replication_dest or replication_dest.lower() == 'none':
|
||||||
|
replication_dest = None
|
||||||
|
else:
|
||||||
|
replication_dest = None
|
||||||
compress = 'compress' in request.form
|
compress = 'compress' in request.form
|
||||||
no_verify_ssl = 'no_verify_ssl' in request.form
|
no_verify_ssl = 'no_verify_ssl' in request.form
|
||||||
schedule_type = request.form.get('schedule_type', 'now')
|
schedule_type = request.form.get('schedule_type', 'now')
|
||||||
|
|||||||
@ -243,8 +243,13 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="form-group">
|
<div class="form-check" style="margin-bottom:15px;">
|
||||||
<label class="form-label" for="replication_dest">Replication target path (optional NFS/local)</label>
|
<input type="checkbox" id="enable_replication" name="enable_replication" onchange="toggleReplication()" />
|
||||||
|
<label for="enable_replication">Enable replication to secondary target (NFS/local)</label>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-group" id="replication_section" style="display:none;">
|
||||||
|
<label class="form-label" for="replication_dest">Replication target path</label>
|
||||||
<input id="replication_dest" class="form-control" type="text" name="replication_dest"
|
<input id="replication_dest" class="form-control" type="text" name="replication_dest"
|
||||||
placeholder="e.g. /mnt/nfs-backup-replica" />
|
placeholder="e.g. /mnt/nfs-backup-replica" />
|
||||||
<div id="repNfsTargets" style="margin-top:10px; display:none;">
|
<div id="repNfsTargets" style="margin-top:10px; display:none;">
|
||||||
@ -730,6 +735,17 @@
|
|||||||
weekdayRow.style.display = '';
|
weekdayRow.style.display = '';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function toggleReplication() {
|
||||||
|
const chk = document.getElementById('enable_replication');
|
||||||
|
const sec = document.getElementById('replication_section');
|
||||||
|
if (chk.checked) {
|
||||||
|
sec.style.display = '';
|
||||||
|
} else {
|
||||||
|
sec.style.display = 'none';
|
||||||
|
document.getElementById('replication_dest').value = '';
|
||||||
|
}
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
|
|||||||
@ -236,8 +236,13 @@
|
|||||||
value="./backups" placeholder="e.g. /mnt/nfs-backup or /data/vmbackups" required />
|
value="./backups" placeholder="e.g. /mnt/nfs-backup or /data/vmbackups" required />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="form-group">
|
<div class="form-check" style="margin-bottom:15px;">
|
||||||
<label class="form-label" for="replication_dest">Replication target path (optional NFS/local)</label>
|
<input type="checkbox" id="enable_replication" name="enable_replication" onchange="toggleReplication()" />
|
||||||
|
<label for="enable_replication">Enable replication to secondary target (NFS/local)</label>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-group" id="replication_section" style="display:none;">
|
||||||
|
<label class="form-label" for="replication_dest">Replication target path</label>
|
||||||
<input id="replication_dest" class="form-control" type="text" name="replication_dest"
|
<input id="replication_dest" class="form-control" type="text" name="replication_dest"
|
||||||
placeholder="e.g. /mnt/nfs-backup-replica" />
|
placeholder="e.g. /mnt/nfs-backup-replica" />
|
||||||
<div id="repNfsTargets" style="margin-top:10px; display:none;">
|
<div id="repNfsTargets" style="margin-top:10px; display:none;">
|
||||||
@ -812,5 +817,16 @@
|
|||||||
weekdayRow.style.display = '';
|
weekdayRow.style.display = '';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function toggleReplication() {
|
||||||
|
const chk = document.getElementById('enable_replication');
|
||||||
|
const sec = document.getElementById('replication_section');
|
||||||
|
if (chk.checked) {
|
||||||
|
sec.style.display = '';
|
||||||
|
} else {
|
||||||
|
sec.style.display = 'none';
|
||||||
|
document.getElementById('replication_dest').value = '';
|
||||||
|
}
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|||||||
@ -230,8 +230,13 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="form-group">
|
<div class="form-check" style="margin-bottom:15px;">
|
||||||
<label class="form-label" for="replication_dest">Replication target path (optional NFS/local)</label>
|
<input type="checkbox" id="enable_replication" name="enable_replication" onchange="toggleReplication()" {% if job.replication_dest %}checked{% endif %} />
|
||||||
|
<label for="enable_replication">Enable replication to secondary target (NFS/local)</label>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-group" id="replication_section" style="{% if not job.replication_dest %}display:none;{% endif %}">
|
||||||
|
<label class="form-label" for="replication_dest">Replication target path</label>
|
||||||
<input id="replication_dest" class="form-control" type="text" name="replication_dest" value="{{ job.replication_dest }}" placeholder="e.g. /mnt/nfs-backup-replica" />
|
<input id="replication_dest" class="form-control" type="text" name="replication_dest" value="{{ job.replication_dest }}" placeholder="e.g. /mnt/nfs-backup-replica" />
|
||||||
|
|
||||||
<div class="nfs-targets" id="repNfsTargets" style="display:none; margin-top: 10px;">
|
<div class="nfs-targets" id="repNfsTargets" style="display:none; margin-top: 10px;">
|
||||||
@ -650,5 +655,16 @@
|
|||||||
weekdayRow.style.display = '';
|
weekdayRow.style.display = '';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function toggleReplication() {
|
||||||
|
const chk = document.getElementById('enable_replication');
|
||||||
|
const sec = document.getElementById('replication_section');
|
||||||
|
if (chk.checked) {
|
||||||
|
sec.style.display = '';
|
||||||
|
} else {
|
||||||
|
sec.style.display = 'none';
|
||||||
|
document.getElementById('replication_dest').value = '';
|
||||||
|
}
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user