knot-dns/tests-extra/tests/zone/backup_lock/test.py

268 lines
9.2 KiB
Python

#!/usr/bin/env python3
'''Test that backup locking and labelling work in backup and restore.'''
from dnstest.test import Test
from dnstest.utils import *
import random
import os
import shutil
def wait_for_file(file, timeout=10):
'''Wait for a file, with timeout'''
for i in range(int(timeout / 0.2)):
if os.path.isfile(file):
break
time.sleep(0.2)
def log_errcode(s):
a = s.rfind("(")
b = s.rfind(")")
if a >= b or a < 0:
return ""
return s[a+1:b]
def check_log_err(server, expect_err):
with open(server.fout) as logf:
for logline in logf:
if "error:" in logline:
last_log = logline
if log_errcode(last_log) != expect_err:
set_err("WRONG ERRCODE")
detail_log("!Unexpected errcode '%s' != '%s'" % (log_errcode(last_log), expect_err))
t = Test()
master = t.server("knot")
backup_dir = os.path.join(master.dir, "backup")
backup_dir_void = os.path.join(master.dir, "backup_void")
backup_dir_keysonly = os.path.join(master.dir, "backup_keysonly")
zones = t.zone_rnd(40, records=80)
t.link(zones, master)
for i in range(0, 3):
master.dnssec(zones[i]).enable = True
master2 = t.server("knot")
zones2 = t.zone("example1.", file_name="example1.file", storage=".") \
+ t.zone("example2.", file_name="example2.file", storage=".") \
+ t.zone("example3.", file_name="example3.file", storage=".")
t.link(zones2, master2)
for i in range(2, 9):
dir_from = os.path.join(t.data_dir, "backup%d" % i)
dir_to = os.path.join(master2.dir, "backup%d" % i)
shutil.copytree(dir_from, dir_to)
globals()["backup%d_dir" % i] = dir_to
if master.valgrind:
master.ctl_params_append = ["-t", "40"]
lockfile = os.path.join(backup_dir, "lock.knot_backup")
labelfile = os.path.join(backup_dir, "knot_backup.label")
if master.valgrind:
master.semantic_check = False
master2.semantic_check = False
t.start()
serials_init = master.zones_wait(zones)
for i in range(10):
for zone in zones:
master.random_ddns(zone)
master.ctl("zone-backup +journal +backupdir %s" % backup_dir, wait=False)
wait_for_file(lockfile, timeout=5)
if master.valgrind: # Without Valgrind the backup is too fast for this test-case
# Attempt to start concurrent backups, expected (requested resource is busy).
try:
master.ctl("zone-backup +backupdir %s" % backup_dir, wait=True)
set_err("CONCURRENT BACKUPS ALLOWED")
except:
pass
check_log_err(master, "requested resource is busy")
# Attempt to start a restore from a backup in progress, expected (malformed data).
try:
master.ctl("zone-restore +backupdir %s" % backup_dir, wait=True)
set_err("RESTORE FROM A PENDING BACKUP ALLOWED")
except:
pass
check_log_err(master, "malformed data")
wait_for_file(labelfile, timeout=60)
# Attempt to start backup into already existing backup, expected (already exists).
try:
master.ctl("zone-backup +backupdir %s" % backup_dir, wait=True)
set_err("BACKUP INTO EXISTING BACKUP ALLOWED")
except:
pass
check_log_err(master, "already exists")
# Attempt to start backup with the "-f" option into already existing backup, expected OK.
try:
master.ctl("-f zone-backup +backupdir %s" % backup_dir, wait=True)
except:
set_err("FORCED BACKUP NOT ALLOWED")
# Attempt to start restore from non-existing backup directory, expected (not exists).
try:
master.ctl("zone-restore +backupdir %s" % backup_dir_void, wait=True)
set_err("RESTORE FROM NON-EXISTING DIRECTORY ALLOWED")
except:
pass
check_log_err(master, "not exists")
# Attempt to start backup to the database storage directory, expected (invalid parameter).
try:
master.ctl("zone-backup +backupdir %s" % master.dir, wait=True)
set_err("BACKUP TO THE DB STORAGE DIRECTORY ALLOWED")
except:
pass
check_log_err(master, "invalid parameter")
# Attempt to start restore from the database storage directory, expected (invalid parameter).
try:
master.ctl("zone-restore +backupdir %s" % master.dir, wait=True)
set_err("RESTORE FROM THE DB STORAGE DIRECTORY ALLOWED")
except:
pass
check_log_err(master, "invalid parameter")
# Attempt to start restore from a non-backup directory, expected (malformed data).
try:
master.ctl("zone-restore +backupdir %s" % t.out_dir, wait=True)
set_err("RESTORE FROM A NON-BACKUP DIRECTORY ALLOWED")
except:
pass
check_log_err(master, "malformed data")
# Do a regular restore, expected OK.
try:
master.ctl("zone-restore +backupdir %s" % backup_dir, wait=True)
except:
set_err("RESTORE NOT ALLOWED")
# Do a regular restore with the "-f" option from the current format, expected OK.
try:
master.ctl("-f zone-restore +backupdir %s" % backup_dir, wait=True)
except:
set_err("FORCED RESTORE NOT ALLOWED")
# Tests with +keysonly filter ##############################################
# Do a keysonly restore from a default ("+kaspdb") backup, expected OK.
try:
master.ctl("zone-restore +keysonly +backupdir %s" % backup_dir, wait=True)
except:
set_err("KEYSONLY RESTORE FROM KASPDB NOT ALLOWED")
# Do a new standard backup (for '+keysonly' testing), expected OK.
try:
master.ctl("zone-backup +backupdir %s" % backup_dir_keysonly, wait=True)
except:
set_err("NEW BACKUP NOT ALLOWED")
# Do a forced keysonly backup into already existing backup, expected OK.
try:
master.ctl("-f zone-backup +keysonly +backupdir %s" % backup_dir_keysonly, wait=True)
except:
set_err("FORCED KEYSONLY BACKUP NOT ALLOWED")
# Do a keysonly restore from a keysonly backup, expected OK.
try:
master.ctl("zone-restore +keysonly +backupdir %s" % backup_dir_keysonly, wait=True)
except:
set_err("KEYSONLY RESTORE NOT ALLOWED")
# Attempt to start restore of various additional data from a keysonly backup, expected (requested data not in backup).
test_filters = ["", \
" +zonefile +nojournal +notimers +nokaspdb +nocatalog +noquic", \
"+nozonefile +journal +notimers +nokaspdb +nocatalog +noquic", \
"+nozonefile +nojournal +timers +nokaspdb +nocatalog +noquic", \
"+nozonefile +nojournal +notimers +kaspdb +nocatalog +noquic", \
"+nozonefile +nojournal +notimers +nokaspdb +catalog +noquic", \
"+nozonefile +nojournal +notimers +nokaspdb +nocatalog +quic"]
for filters in test_filters:
try:
master.ctl("zone-restore %s +backupdir %s" % (filters, backup_dir_keysonly), wait=True)
set_err("DATA RESTORE FROM KEYSONLY BACKUP ALLOWED")
except:
pass
check_log_err(master, "requested data not in backup")
# Tests with preconfigured backups, server master2. #############################
# Attempt to restore without the "-f" option from the format 1 backup, expected (malformed data).
try:
master2.ctl("zone-restore +backupdir %s" % backup2_dir, wait=True)
set_err("RESTORE FROM OBSOLETE FORMAT ALLOWED")
except:
pass
check_log_err(master2, "malformed data")
# Do a restore with the "-f" option from a format 1 backup, expected OK.
try:
master2.ctl("-f zone-restore +backupdir %s" % backup2_dir, wait=True)
except:
set_err("FORCED RESTORE FROM OBSOLETE FORMAT NOT ALLOWED")
# Attempt to restore from a labelled, but locked backup, expected (requested resource is busy).
try:
master2.ctl("zone-restore +backupdir %s" % backup3_dir, wait=True)
set_err("RESTORE FROM A LOCKED BACKUP ALLOWED")
except:
pass
check_log_err(master2, "requested resource is busy")
# Attempt to restore from an unlabelled backup, expected (malformed data).
try:
master2.ctl("zone-restore +backupdir %s" % backup4_dir, wait=True)
set_err("RESTORE FROM AN UNLABELLED BACKUP ALLOWED")
except:
pass
check_log_err(master2, "malformed data")
# Attempt to restore from a backup with corrupted label, expected (malformed data).
try:
master2.ctl("-f zone-restore +backupdir %s" % backup5_dir, wait=True)
set_err("RESTORE FROM BACKUP WITH A CORRUPT LABEL ALLOWED")
except:
pass
check_log_err(master2, "malformed data")
# Attempt to restore from unsupported backup format number, expected (operation not supported).
try:
master2.ctl("-f zone-restore +backupdir %s" % backup6_dir, wait=True)
set_err("RESTORE FROM UNSUPPORTED BACKUP FORMAT VERSION ALLOWED")
except:
pass
check_log_err(master2, "operation not supported")
# Attempt to restore from non-existant backup format number, expected (malformed data).
try:
master2.ctl("-f zone-restore +backupdir %s" % backup7_dir, wait=True)
set_err("RESTORE FROM NON-EXISTANT BACKUP FORMAT VERSION ALLOWED")
except:
pass
check_log_err(master2, "malformed data")
# Attempt to restore from a backup made by incompatible CPU architecture (incompatible CPU architecture).
try:
master2.ctl("zone-restore +backupdir %s" % backup8_dir, wait=True)
set_err("RESTORE FROM INCOMPATIBLE ARCHITECTURE ALLOWED")
except:
pass
check_log_err(master2, "incompatible CPU architecture")
# Attempt to restore a zonefile from a backup made by incompatible CPU architecture, expected OK.
try:
master2.ctl("zone-restore +zonefile +notimers +nokaspdb +nojournal +nocatalog +backupdir %s" % backup8_dir, wait=True)
except:
set_err("ZONEFILE RESTORE FROM INCOMPATIBLE CPU FAILED")
t.stop()