1+ import re
2+
3+
4+ from virttest import libvirt_version
5+ from virttest import libvirt_vm
6+ from virttest import migration
7+ from virttest import remote
8+ from virttest import utils_net
9+ from virttest import utils_package
10+ from virttest import virsh
11+ from provider .guest_os_booting import guest_os_booting_base as guest_os
12+
13+ from virttest .libvirt_xml import vm_xml
14+ from virttest .utils_test import libvirt
15+ from virttest .utils_libvirt import libvirt_network
16+ from virttest .utils_libvirt import libvirt_vmxml
17+ from provider .virtual_network import network_base
18+ from provider .interface import interface_base
19+ from provider .migration import base_steps
20+
21+
22+
23+ def run (test , params , env ):
24+ """
25+ Test migration with bridge type interface
26+ 1. Setup bridge and virtual network according to bridge type
27+ 2. Migrate to target host
28+ 3. Check on target host for network functions:
29+ - Guest ping outside
30+ - Check for multiqueue
31+ - Check multiqueues in VM live XML (should have <driver ... queues='5'>)
32+ 4. Migrate back from dst to src
33+
34+ :param test: test object
35+ :param params: Dictionary with the test parameters
36+ :param env: Dictionary with test environment.
37+ """
38+ def check_multiqueue_in_guest (vm_session ):
39+ """
40+ Check multiqueue configuration inside the guest
41+ """
42+ test .log .info ("Checking multiqueue configuration in guest" )
43+ # Get network interface name
44+ guest_iface_info = vm_session .cmd_output ("ip --color=never l" ).strip ()
45+ iface_name = re .findall (
46+ r"^\d+: (\S+?)[@:].*state UP.*$" , guest_iface_info , re .MULTILINE )[0 ]
47+ if not iface_name :
48+ test .fail ("Failed to get network interface name in guest" )
49+
50+ maximum , current = utils_net .get_channel_info (vm_session , iface_name )
51+ if maximum .get ("Combined" , 0 ) != iface_queues :
52+ test .fail ("Expected Pre-set maximums Combined: 5, but got: %d" % maximum )
53+ if current .get ("Combined" , 0 ) != iface_queues :
54+ test .fail ("Expected Current hardware settings Combined: 5, but got: %d" % current )
55+
56+ test .log .info ("Setting combined queues to 3 for %s" , iface_name )
57+ utils_net .set_channel (vm_session , iface_name , "combined" , new_queues )
58+
59+ _ , verify_current = utils_net .get_channel_info (vm_session , iface_name ).get ("Combined" , 0 )
60+ if verify_current != new_queues :
61+ test .fail ("Failed to set combined queues, current value: %d" % verify_current )
62+
63+ def setup_vm_interface ():
64+ """
65+ Setup VM interface according to configuration
66+ """
67+ test .log .info ("Setting up VM interface" )
68+
69+ # Get interface configuration from params
70+ if interface_timing == "hotplug" :
71+ # Hot-plug interface using helper function
72+ iface_xml = libvirt .modify_vm_iface (vm_name , "get_xml" , iface_dict )
73+ if not vm .is_alive ():
74+ vm .start ()
75+ vm .wait_for_login ()
76+ result = virsh .attach_device (vm_name , iface_xml , flagstr = "--live" , debug = True )
77+ if result .exit_status :
78+ test .fail ("Failed to hotplug interface: %s" % result .stderr_text )
79+ else :
80+ # Add interface to XML using setup_attrs pattern
81+ vmxml = vm_xml .VMXML .new_from_inactive_dumpxml (vm_name )
82+ vmxml .remove_all_device_by_type ('interface' )
83+
84+ iface = interface_base .create_iface (iface_dict ['type' ], iface_dict )
85+ vmxml .add_device (iface )
86+ vmxml .sync ()
87+
88+
89+ def setup_test ():
90+ """
91+ Setup test environment for migration with bridge type interface
92+ """
93+ test .log .info ("Setting up test environment" )
94+ if bridge_type == "linux" :
95+ pass
96+ # utils_net.create_linux_bridge_tmux(bridge_name)
97+ # utils_net.create_linux_bridge_tmux(bridge_name, session=remote_session)
98+
99+ elif bridge_type == "ovs" :
100+ # Create OVS bridge
101+ status , stdout = utils_net .create_ovs_bridge (ovs_bridge_name , ip_options = '-color=never' )
102+ if status :
103+ test .fail ("Failed to create ovs bridge on local. Status: %s, Stdout: %s" % (status , stdout ))
104+
105+ # Create same bridge on remote host
106+ status , stdout = utils_net .create_ovs_bridge (ovs_bridge_name , session = remote_session , ip_options = '-color=never' )
107+ if status :
108+ test .fail ("Failed to create ovs bridge on remote. Status: %s, Stdout: %s" % (status , stdout ))
109+
110+ # Create virtual network for OVS bridge
111+ libvirt_network .create_or_del_network (network_dict , remote_args = remote_virsh_dargs )
112+ test .log .info ("dest: network created" )
113+ libvirt_network .create_or_del_network (network_dict )
114+ test .log .info ("localhost: network created" )
115+
116+ # Setup NFS shared storage for migration
117+ migration_test .migrate_pre_setup (dest_uri , params )
118+
119+ libvirt .set_vm_disk (vm , params )
120+ setup_vm_interface ()
121+
122+ test .log .debug ("Guest xml after starting:\n %s" , vm_xml .VMXML .new_from_dumpxml (vm_name ))
123+
124+ def run_test ():
125+ """
126+ Run the main test: migration and verification
127+ """
128+ test .log .info ("Starting migration test" )
129+
130+ # Check local guest network connection before migration
131+ if vm .serial_console is not None :
132+ vm .cleanup_serial_console ()
133+ vm .create_serial_console ()
134+ vm_session = vm .wait_for_serial_login (timeout = 240 )
135+
136+ if not utils_package .package_install ('dhcp-client' , session = vm_session ):
137+ test .error ("Failed to install dhcp-client on guest." )
138+ utils_net .restart_guest_network (vm_session )
139+
140+ test .log .info ("Checking VM network connectivity before migration" )
141+ ips = {'outside_ip' : remote_ip }
142+ network_base .ping_check (params , ips , vm_session )
143+
144+ test .log .info ("Migrating VM to target host" )
145+ migration_obj = base_steps .MigrationBase (test , vm , params )
146+ migration_obj .setup_connection ()
147+ migration_obj .run_migration ()
148+
149+ test .log .info ("Checking VM network connectivity on target host" )
150+ vm .connect_uri = dest_uri
151+ if vm .serial_console is not None :
152+ vm .cleanup_serial_console ()
153+ vm .create_serial_console ()
154+ vm_session_after_mig = vm .wait_for_serial_login (timeout = 240 )
155+ vm_session_after_mig .cmd ("dhclient -r; dhclient" )
156+
157+ test .log .info ("Testing guest ping to outside" )
158+ ips = {'outside_ip' : remote_ip }
159+ network_base .ping_check (params , ips , vm_session_after_mig )
160+
161+ test .log .info ("Checking multiqueue in guest" )
162+ check_multiqueue_in_guest (vm_session_after_mig )
163+
164+ test .log .info ("Checking multiqueue in VM XML" )
165+ libvirt_vmxml .check_guest_xml_by_xpaths (
166+ vm_xml .VMXML .new_from_dumpxml (vm_name , virsh_instance = virsh_session_remote ),
167+ expected_xpath )
168+
169+ if migrate_vm_back :
170+ test .log .info ("Migrating VM back to source host" )
171+ migration_obj = base_steps .MigrationBase (test , vm , params )
172+ migration_obj .run_migration_back ()
173+
174+ def teardown_test ():
175+ """
176+ Cleanup test environment
177+ """
178+ test .log .info ("Cleaning up test environment" )
179+ vm .connect_uri = bk_uri
180+ migration_test .cleanup_vm (vm , dest_uri )
181+
182+ # Recovery VM XML configuration
183+ test .log .info ("Recovery VM XML configuration" )
184+ orig_config_xml .sync ()
185+
186+ # Cleanup bridges
187+ if bridge_type == "linux" :
188+ pass
189+ # utils_net.delete_linux_bridge_tmux(bridge_name)
190+ # utils_net.delete_linux_bridge_tmux(bridge_name, session=remote_session)
191+ elif bridge_type == "ovs" :
192+ utils_net .delete_ovs_bridge (ovs_bridge_name , ip_options = '-color=never' )
193+ utils_net .delete_ovs_bridge (ovs_bridge_name , session = remote_session , ip_options = '-color=never' )
194+
195+ # Cleanup networks
196+ libvirt_network .create_or_del_network (network_dict , is_del = True , remote_args = remote_virsh_dargs )
197+ libvirt_network .create_or_del_network (network_dict , is_del = True )
198+
199+ if migrate_vm_back :
200+ ssh_connection = None
201+ if 'ssh_connection' in locals ():
202+ ssh_connection .auto_recover = True
203+ migration_test .migrate_pre_setup (src_uri , params , cleanup = True )
204+
205+ # Remove local NFS image
206+ test .log .info ("Remove local NFS image" )
207+ source_file = params .get ("source_file" )
208+ if source_file :
209+ libvirt .delete_local_disk ("file" , path = source_file )
210+
211+ # Initialize migration test
212+ migration_test = migration .MigrationTest ()
213+ migration_test .check_parameters (params )
214+
215+ libvirt_version .is_libvirt_feature_supported (params )
216+
217+ # Params to update disk using shared storage
218+ params ["disk_type" ] = params .get ("disk_type" , "file" )
219+ params ["disk_source_protocol" ] = params .get ("disk_source_protocol" , "netfs" )
220+ params ["mnt_path_name" ] = params .get ("nfs_mount_dir" )
221+
222+ # Local variables
223+ server_ip = params .get ("server_ip" )
224+ server_user = params .get ("server_user" )
225+ server_pwd = params .get ("server_pwd" )
226+ remote_ip = params .get ("remote_ip" )
227+ bridge_name = params .get ("bridge_name" )
228+ bridge_type = params .get ("bridge_type" )
229+ ovs_bridge_name = params .get ("ovs_bridge_name" )
230+ network_dict = eval (params .get ("network_dict" , "{}" ))
231+ interface_timing = params .get ("interface_timing" )
232+ iface_queues = params .get ("iface_queues" )
233+ new_queues = params .get ("new_queues" )
234+
235+ migrate_vm_back = "yes" == params .get ("migrate_vm_back" )
236+
237+ remote_virsh_dargs = {'remote_ip' : server_ip , 'remote_user' : server_user ,
238+ 'remote_pwd' : server_pwd , 'unprivileged_user' : params .get ("unprivileged_user" ),
239+ 'ssh_remote_auth' : params .get ("ssh_remote_auth" )}
240+
241+ # params for migration connection
242+ params ["virsh_migrate_desturi" ] = libvirt_vm .complete_uri (
243+ params .get ("migrate_dest_host" ))
244+ params ["virsh_migrate_connect_uri" ] = libvirt_vm .complete_uri (
245+ params .get ("migrate_source_host" ))
246+ src_uri = params .get ("virsh_migrate_connect_uri" )
247+ dest_uri = params .get ("virsh_migrate_desturi" )
248+ expected_xpath = params .get ("expected_xpath" )
249+ iface_dict = eval (params .get ("iface_dict" , "{}" ))
250+
251+ vm_name = guest_os .get_vm (params )
252+ vm = env .get_vm (vm_name )
253+ vm .verify_alive ()
254+ bk_uri = vm .connect_uri
255+
256+ # For safety reasons, we'd better back up xmlfile
257+ new_xml = vm_xml .VMXML .new_from_inactive_dumpxml (vm_name )
258+ orig_config_xml = new_xml .copy ()
259+
260+ # Create remote session and virsh instance
261+ remote_session = remote .remote_login ("ssh" , server_ip , "22" ,
262+ server_user , server_pwd , r'[$#%]' )
263+ virsh_session_remote = virsh .VirshPersistent (** remote_virsh_dargs )
264+
265+ try :
266+ setup_test ()
267+ run_test ()
268+ finally :
269+ teardown_test ()
270+ if remote_session :
271+ remote_session .close ()
272+ if virsh_session_remote :
273+ virsh_session_remote .close_session ()
0 commit comments