Skip to content

Commit 03f61f8

Browse files
committed
Inc_backup: Automate incremental backup lifecycle test cases
Automate cases: RHEL-187642 pull mode backup and managed save vm together RHEL-187641 pull mode backup and save vm together RHEL-199045 Start an existing backup job after libvirtd restarted RHEL-199046 kill qemu process between libvirtd stop/start when there is an existing pull-mode backup job Signed-off-by: Meina Li <meili@redhat.com>
1 parent 9aa7dea commit 03f61f8

File tree

2 files changed

+261
-0
lines changed

2 files changed

+261
-0
lines changed
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
- incremental_backup.lifecycle:
2+
type = incremental_backup_lifecycle
3+
start_vm = "no"
4+
disk_type = "file"
5+
target_disk = "vda"
6+
disk_dict = {"type_name": ${disk_type}, "target":{"dev": "%s", "bus": "virtio"}, "driver": {"name": "qemu", "type": "qcow2"}}
7+
full_checkpoint = "check_full"
8+
inc_checkpoint = "check_inc1"
9+
nbd_hostname = "localhost"
10+
nbd_tcp_port = "10809"
11+
backup_dict = {'mode': 'pull', 'server': {'name': '${nbd_hostname}', 'port': '${nbd_tcp_port}'}, 'disks': [{'name': 'vda', 'backup': 'yes', 'type': 'file', 'scratch': {'attrs': {'file': '%s'}}}]}
12+
checkpoint_dict = {'name': '%s', 'disks': [{'name': 'vda', 'checkpoint': 'bitmap'}]}
13+
inc_backup_dict = {'mode': 'pull', 'incremental': '${full_checkpoint}', 'server': {'name': '${nbd_hostname}', 'port': '${nbd_tcp_port}'}, 'disks': [{'name': 'vda', 'backup': 'yes', 'type': 'file', 'scratch': {'attrs': {'file': '%s'}}}]}
14+
variants test_case:
15+
- save_vm:
16+
expected_error = "Timed out during operation: cannot acquire state change lock.*remoteDispatchDomainBackupBegin"
17+
- managedsave:
18+
expected_error = "Timed out during operation: cannot acquire state change lock.*remoteDispatchDomainBackupBegin"
19+
- restart_service:
20+
expected_error = "Timed out during operation: cannot acquire state change lock.*monitor"
21+
- kill_qemu_process:
Lines changed: 240 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,240 @@
1+
import os
2+
import ast
3+
4+
from avocado.utils import process
5+
from virttest import data_dir
6+
from virttest import virsh
7+
from virttest import utils_backup
8+
from virttest.utils_libvirtd import Libvirtd
9+
10+
from virttest.libvirt_xml import vm_xml
11+
from virttest.libvirt_xml import backup_xml
12+
from virttest.libvirt_xml import checkpoint_xml
13+
from virttest.utils_test import libvirt
14+
15+
16+
def prepare_backup_xml(test, params, backup_type):
17+
"""
18+
Prepare the backup xml.
19+
20+
:return: return the backup options and the scratch file.
21+
"""
22+
scratch_file = data_dir.get_data_dir() + '/scratch_file_%s' % backup_type
23+
backup_dict = ast.literal_eval(params.get("backup_dict", "{}") % scratch_file)
24+
full_checkpoint = params.get("full_checkpoint")
25+
inc_checkpoint = params.get("inc_checkpoint")
26+
if backup_type == "inc":
27+
backup_dict.update({'incremental': full_checkpoint})
28+
checkpoint_dict = ast.literal_eval(params.get("checkpoint_dict") % inc_checkpoint)
29+
else:
30+
checkpoint_dict = ast.literal_eval(params.get("checkpoint_dict") % full_checkpoint)
31+
backup_dev = backup_xml.BackupXML()
32+
backup_dev.setup_attrs(**backup_dict)
33+
test.log.debug("The backup xml is %s." % backup_dev)
34+
checkpoint_dev = checkpoint_xml.CheckpointXML()
35+
checkpoint_dev.setup_attrs(**checkpoint_dict)
36+
backup_options = backup_dev.xml + " " + checkpoint_dev.xml
37+
return backup_options
38+
39+
40+
def start_full_backup(test, params):
41+
"""
42+
Start a full backup.
43+
44+
:return: return the backup file path.
45+
"""
46+
vm_name = params.get("main_vm")
47+
backup_file_path = data_dir.get_data_dir() + '/full.backup'
48+
target_disk = params.get("target_disk")
49+
nbd_hostname = params.get("nbd_hostname")
50+
nbd_tcp_port = params.get("nbd_tcp_port")
51+
nbd_params = {
52+
'nbd_protocol': "tcp",
53+
'nbd_hostname': nbd_hostname,
54+
'nbd_tcp_port': nbd_tcp_port,
55+
'nbd_export': target_disk
56+
}
57+
backup_options = prepare_backup_xml(test, params, backup_type="full")
58+
virsh.backup_begin(vm_name, backup_options, debug=True)
59+
try:
60+
utils_backup.pull_full_backup_to_file(nbd_params, backup_file_path)
61+
except Exception as details:
62+
test.fail("Fail to get full backup data: %s" % details)
63+
test.log.debug("Full backup to %s" % backup_file_path)
64+
return backup_file_path
65+
66+
67+
def start_incremental_backup(test, params):
68+
"""
69+
Start an incremental backup.
70+
71+
:return: return the backup file path.
72+
"""
73+
vm_name = params.get("main_vm")
74+
backup_file_path = data_dir.get_data_dir() + '/inc.backup'
75+
nbd_hostname = params.get("nbd_hostname")
76+
nbd_tcp_port = params.get("nbd_tcp_port")
77+
target_disk = params.get("target_disk")
78+
nbd_bitmap_name = "backup-" + target_disk
79+
original_disk_size = params.get("original_disk_size", "10G")
80+
nbd_params = {
81+
'nbd_hostname': nbd_hostname,
82+
'nbd_tcp_port': nbd_tcp_port,
83+
'nbd_export': target_disk
84+
}
85+
backup_options = prepare_backup_xml(test, params, backup_type="inc")
86+
virsh.backup_begin(vm_name, backup_options, debug=True, ignore_status=False)
87+
try:
88+
utils_backup.pull_incremental_backup_to_file(
89+
nbd_params, backup_file_path, nbd_bitmap_name,
90+
original_disk_size)
91+
except Exception as details:
92+
test.fail("Fail to get incremental backup data: %s" % details)
93+
return backup_file_path
94+
95+
96+
def test_save_vm(test, params, backup_file_list):
97+
"""
98+
Test save vm with incremental backup.
99+
100+
:return: return the list of backup files.
101+
"""
102+
if backup_file_list is None:
103+
backup_file_list = []
104+
vm_name = params.get("main_vm")
105+
expected_error = params.get("expected_error")
106+
test.log.info("Start full backup.")
107+
backup_file_path = start_full_backup(test, params)
108+
backup_file_list.append(backup_file_path)
109+
110+
test.log.info("Do save before abort the backup job.")
111+
save_file = data_dir.get_data_dir() + '/%s.save' % vm_name
112+
save_result = virsh.save(vm_name, save_file, debug=True)
113+
libvirt.check_result(save_result, expected_error)
114+
abort_result = virsh.domjobabort(vm_name)
115+
libvirt.check_exit_status(abort_result)
116+
117+
test.log.info("Do save after abort the backup job.")
118+
virsh.save(vm_name, save_file, debug=True, ignore_status=False)
119+
virsh.restore(save_file, debug=True, ignore_status=False)
120+
if os.path.exists(save_file):
121+
os.remove(save_file)
122+
123+
test.log.info("Start incremental backup.")
124+
backup_file_path = start_incremental_backup(test, params)
125+
backup_file_list.append(backup_file_path)
126+
return backup_file_list
127+
128+
129+
def test_managedsave(test, params, backup_file_list):
130+
"""
131+
Test managedsave vm with incremental backup.
132+
133+
:return: return the list of backup files
134+
"""
135+
if backup_file_list is None:
136+
backup_file_list = []
137+
vm_name = params.get("main_vm")
138+
expected_error = params.get("expected_error")
139+
test.log.info("Start full backup.")
140+
backup_file_path = start_full_backup(test, params)
141+
backup_file_list.append(backup_file_path)
142+
143+
test.log.info("Do managedsave before abort the backup job.")
144+
save_result = virsh.managedsave(vm_name, debug=True)
145+
libvirt.check_result(save_result, expected_error)
146+
virsh.domjobabort(vm_name)
147+
148+
test.log.info("Do managedsave after abort the backup job.")
149+
virsh.managedsave(vm_name, debug=True, ignore_status=False)
150+
virsh.start(vm_name)
151+
test.log.info("Start incremental backup.")
152+
backup_file_path = start_incremental_backup(test, params)
153+
backup_file_list.append(backup_file_path)
154+
return backup_file_list
155+
156+
157+
def test_restart_service(test, params, backup_file_list):
158+
"""
159+
Test restart libvirtd/virtqemud service after backup.
160+
161+
:return: return the list of backup files.
162+
"""
163+
if backup_file_list is None:
164+
backup_file_list = []
165+
vm_name = params.get("main_vm")
166+
expected_error = params.get("expected_error")
167+
test.log.info("Start full backup.")
168+
backup_file_path = start_full_backup(test, params)
169+
backup_file_list.append(backup_file_path)
170+
171+
test.log.info("Restart libvirtd/virtqemud service.")
172+
Libvirtd().restart()
173+
174+
test.log.info("Start incremental backup")
175+
backup_options = prepare_backup_xml(test, params, backup_type="inc")
176+
result = virsh.backup_begin(vm_name, backup_options, debug=True)
177+
libvirt.check_result(result, expected_error)
178+
return backup_file_list
179+
180+
181+
def test_kill_qemu_process(test, params, backup_file_list):
182+
"""
183+
Kill qemu process between libvirtd stop/start when there is an existing pull-mode backup job.
184+
185+
:return: return the list of backup files.
186+
"""
187+
if backup_file_list is None:
188+
backup_file_list = []
189+
vm_name = params.get("main_vm")
190+
test.log.info("Start full backup.")
191+
backup_file_path = start_full_backup(test, params)
192+
backup_file_list.append(backup_file_path)
193+
194+
test.log.info("Stop libvirt daemon and kill qemu process.")
195+
Libvirtd().stop()
196+
process.run("kill -9 `pidof qemu-kvm`", shell=True, ignore_status=False)
197+
198+
test.log.info("Start libvirt daemon and start the guest again.")
199+
Libvirtd().start()
200+
dom_state = virsh.domstate(vm_name).stdout.strip()
201+
if "shut off" not in dom_state:
202+
test.fail("The guest doesn't shutoff as expected!")
203+
start_result = virsh.start(vm_name, debug=True)
204+
libvirt.check_exit_status(start_result)
205+
return backup_file_list
206+
207+
208+
def run(test, params, env):
209+
"""
210+
Test vm lifecycle with incremental backup
211+
"""
212+
vm_name = params.get("main_vm")
213+
vm = env.get_vm(vm_name)
214+
case = params.get('test_case', '')
215+
216+
vmxml = vm_xml.VMXML.new_from_inactive_dumpxml(vm_name)
217+
vmxml_backup = vmxml.copy()
218+
219+
test_functions = {
220+
'save_vm': test_save_vm,
221+
'managedsave': test_managedsave,
222+
'restart_service': test_restart_service,
223+
'kill_qemu_process': test_kill_qemu_process
224+
}
225+
run_test = test_functions.get(case)
226+
if not run_test:
227+
test.error(f"Unknown test case: {case}")
228+
229+
try:
230+
backup_file_list = None
231+
if not vm.is_alive():
232+
vm.start()
233+
backup_file_list = run_test(test, params, backup_file_list)
234+
finally:
235+
utils_backup.clean_checkpoints(vm_name)
236+
vmxml_backup.sync()
237+
if backup_file_list:
238+
for file in backup_file_list:
239+
if os.path.exists(file):
240+
os.remove(file)

0 commit comments

Comments
 (0)