-
Notifications
You must be signed in to change notification settings - Fork 181
Add case to support download/upload file over ipv6 #6673
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,24 @@ | ||
| - virtual_network.qemu_test.transfer_file_over_ipv6: image_copy | ||
| create_vm_libvirt = yes | ||
| master_images_clone = img1 | ||
| kill_vm_libvirt = yes | ||
| ovmf: | ||
| kill_vm_libvirt_options = --nvram | ||
| type = transfer_file_over_ipv6 | ||
| vms = "vm1 vm2" | ||
| image_snapshot = yes | ||
| filesize = 4096 | ||
| file_trans_timeout = 2400 | ||
| file_md5_check_timeout = 600 | ||
| dd_cmd = "dd if=/dev/zero of=%s bs=1M count=%d" | ||
| Linux: | ||
| tmp_dir = "/var/tmp/" | ||
| Windows: | ||
| tmp_dir = "C:\\" | ||
| variants: | ||
| - remote_addr: | ||
| link_local_ipv6_addr = false | ||
| - link_local_addr: | ||
| link_local_ipv6_addr = true | ||
| Host_RHEL.m7, Host_RHEL.m8: | ||
| using_guest_interface = true | ||
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,197 @@ | ||||||||||||||||||||||
| import os | ||||||||||||||||||||||
| import re | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| from avocado.utils import crypto, process | ||||||||||||||||||||||
| from virttest import error_context, remote, utils_misc, utils_net | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
|
|
||||||||||||||||||||||
| @error_context.context_aware | ||||||||||||||||||||||
| def run(test, params, env): | ||||||||||||||||||||||
| """ | ||||||||||||||||||||||
| Test Step | ||||||||||||||||||||||
| 1. boot up two virtual machine | ||||||||||||||||||||||
| 2. For linux guest,Transfer data: | ||||||||||||||||||||||
| host <--> guest1 <--> guest2 <-->host via ipv6 | ||||||||||||||||||||||
| For windows guest,Transfer data: | ||||||||||||||||||||||
| host <--> guest1&guest2 via ipv6 | ||||||||||||||||||||||
| 3. after data transfer, check data have no change | ||||||||||||||||||||||
| Params: | ||||||||||||||||||||||
| :param test: LIBVIRT test object | ||||||||||||||||||||||
| :param params: Dictionary with the test parameters | ||||||||||||||||||||||
| :param env: Dictionary with test environment. | ||||||||||||||||||||||
| """ | ||||||||||||||||||||||
| timeout = params.get_numeric("login_timeout", "360") | ||||||||||||||||||||||
| client = params.get("file_transfer_client") | ||||||||||||||||||||||
| port = params.get("file_transfer_port") | ||||||||||||||||||||||
| password = params.get("password") | ||||||||||||||||||||||
| username = params.get("username") | ||||||||||||||||||||||
| tmp_dir = params["tmp_dir"] | ||||||||||||||||||||||
| filesize = params.get_numeric("filesize", "4096") | ||||||||||||||||||||||
| dd_cmd = params["dd_cmd"] | ||||||||||||||||||||||
| file_trans_timeout = params.get_numeric("file_trans_timeout", "1200") | ||||||||||||||||||||||
| file_md5_check_timeout = params.get_numeric("file_md5_check_timeout", "600") | ||||||||||||||||||||||
| link_local_ipv6_addr = params.get_boolean("link_local_ipv6_addr") | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| def get_file_md5sum(file_name, session, timeout): | ||||||||||||||||||||||
| """ | ||||||||||||||||||||||
| Get file md5sum from guest. | ||||||||||||||||||||||
| """ | ||||||||||||||||||||||
| test.log.info("Get md5sum of the file:'%s'", file_name) | ||||||||||||||||||||||
| s, o = session.cmd_status_output("md5sum %s" % file_name, timeout=timeout) | ||||||||||||||||||||||
| if s != 0: | ||||||||||||||||||||||
| test.error("Get file md5sum failed as %s" % o) | ||||||||||||||||||||||
| return re.findall(r"\w{32}", o)[0] | ||||||||||||||||||||||
|
Comment on lines
+35
to
+43
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Verify Windows compatibility for MD5 calculation. The Consider adding OS-specific MD5 command logic: def get_file_md5sum(file_name, session, timeout):
"""
Get file md5sum from guest.
"""
test.log.info("Get md5sum of the file:'%s'", file_name)
- s, o = session.cmd_status_output("md5sum %s" % file_name, timeout=timeout)
+ if params.get("os_type") == "linux":
+ cmd = "md5sum %s" % file_name
+ else:
+ cmd = "certutil -hashfile %s MD5" % file_name
+ s, o = session.cmd_status_output(cmd, timeout=timeout)
if s != 0:
test.error("Get file md5sum failed as %s" % o)
return re.findall(r"\w{32}", o)[0]
🤖 Prompt for AI Agents |
||||||||||||||||||||||
|
|
||||||||||||||||||||||
| sessions = {} | ||||||||||||||||||||||
| addresses = {} | ||||||||||||||||||||||
| inet_name = {} | ||||||||||||||||||||||
| vms = [] | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| error_context.context("Boot vms for test", test.log.info) | ||||||||||||||||||||||
| for vm_name in params.get("vms", "vm1 vm2").split(): | ||||||||||||||||||||||
| vms.append(env.get_vm(vm_name)) | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| host_ifname = params.get("netdst") if link_local_ipv6_addr else None | ||||||||||||||||||||||
| host_address = utils_net.get_host_ip_address( | ||||||||||||||||||||||
| params, ip_ver="ipv6", linklocal=link_local_ipv6_addr | ||||||||||||||||||||||
| ) | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| error_context.context("Get ipv6 address of host: %s" % host_address, test.log.info) | ||||||||||||||||||||||
| for vm in vms: | ||||||||||||||||||||||
| vm.verify_alive() | ||||||||||||||||||||||
| sessions[vm] = vm.wait_for_login(timeout=timeout) | ||||||||||||||||||||||
| if params.get("os_type") == "linux": | ||||||||||||||||||||||
| inet_name[vm] = utils_net.get_linux_ifname( | ||||||||||||||||||||||
| sessions[vm], vm.get_mac_address() | ||||||||||||||||||||||
| ) | ||||||||||||||||||||||
| addresses[vm] = utils_net.get_guest_ip_addr( | ||||||||||||||||||||||
| sessions[vm], | ||||||||||||||||||||||
| vm.get_mac_address(), | ||||||||||||||||||||||
| params.get("os_type"), | ||||||||||||||||||||||
| ip_version="ipv6", | ||||||||||||||||||||||
| linklocal=link_local_ipv6_addr, | ||||||||||||||||||||||
| ) | ||||||||||||||||||||||
| if link_local_ipv6_addr is False and addresses[vm] is None: | ||||||||||||||||||||||
| test.cancel("Your guest can not get remote IPv6 address.") | ||||||||||||||||||||||
| error_context.context( | ||||||||||||||||||||||
| "Get ipv6 address of %s: %s" % (vm.name, addresses[vm]), test.log.info | ||||||||||||||||||||||
| ) | ||||||||||||||||||||||
|
Comment on lines
+74
to
+78
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Remove unreachable code after test.cancel. Lines 76-78 are unreachable because Apply this diff to remove unreachable code and move the context logging before the cancel: - if link_local_ipv6_addr is False and addresses[vm] is None:
- test.cancel("Your guest can not get remote IPv6 address.")
- error_context.context(
- "Get ipv6 address of %s: %s" % (vm.name, addresses[vm]), test.log.info
- )
+ error_context.context(
+ "Get ipv6 address of %s: %s" % (vm.name, addresses[vm]), test.log.info
+ )
+ if link_local_ipv6_addr is False and addresses[vm] is None:
+ test.cancel("Your guest can not get remote IPv6 address.")📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||||
|
|
||||||||||||||||||||||
| # prepare test data | ||||||||||||||||||||||
| guest_path = tmp_dir + "src-%s" % utils_misc.generate_random_string(8) | ||||||||||||||||||||||
| dest_path = tmp_dir + "dst-%s" % utils_misc.generate_random_string(8) | ||||||||||||||||||||||
| host_path = os.path.join( | ||||||||||||||||||||||
| test.tmpdir, "tmp-%s" % utils_misc.generate_random_string(8) | ||||||||||||||||||||||
| ) | ||||||||||||||||||||||
| test.log.info("Test setup: Creating %dMB file on host", filesize) | ||||||||||||||||||||||
| process.run(dd_cmd % (host_path, filesize), shell=True) | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| try: | ||||||||||||||||||||||
| src_md5 = crypto.hash_file(host_path, algorithm="md5") | ||||||||||||||||||||||
| error_context.context("md5 value of data from src: %s" % src_md5, test.log.info) | ||||||||||||||||||||||
| # transfer data | ||||||||||||||||||||||
| for vm in vms: | ||||||||||||||||||||||
| error_context.context( | ||||||||||||||||||||||
| "Transfer data from host to %s" % vm.name, test.log.info | ||||||||||||||||||||||
| ) | ||||||||||||||||||||||
| remote.copy_files_to( | ||||||||||||||||||||||
| addresses[vm], | ||||||||||||||||||||||
| client, | ||||||||||||||||||||||
| username, | ||||||||||||||||||||||
| password, | ||||||||||||||||||||||
| port, | ||||||||||||||||||||||
| host_path, | ||||||||||||||||||||||
| guest_path, | ||||||||||||||||||||||
| timeout=file_trans_timeout, | ||||||||||||||||||||||
| interface=host_ifname, | ||||||||||||||||||||||
| ) | ||||||||||||||||||||||
| dst_md5 = get_file_md5sum( | ||||||||||||||||||||||
| guest_path, sessions[vm], timeout=file_md5_check_timeout | ||||||||||||||||||||||
| ) | ||||||||||||||||||||||
| error_context.context( | ||||||||||||||||||||||
| "md5 value of data in %s: %s" % (vm.name, dst_md5), test.log.info | ||||||||||||||||||||||
| ) | ||||||||||||||||||||||
| if dst_md5 != src_md5: | ||||||||||||||||||||||
| test.fail("File changed after transfer host -> %s" % vm.name) | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| if params.get("os_type") == "linux": | ||||||||||||||||||||||
| for vm_src in addresses: | ||||||||||||||||||||||
| for vm_dst in addresses: | ||||||||||||||||||||||
| if vm_src != vm_dst: | ||||||||||||||||||||||
| error_context.context( | ||||||||||||||||||||||
| "Transferring data from %s to %s" | ||||||||||||||||||||||
| % (vm_src.name, vm_dst.name), | ||||||||||||||||||||||
| test.log.info, | ||||||||||||||||||||||
| ) | ||||||||||||||||||||||
| if params.get_boolean("using_guest_interface"): | ||||||||||||||||||||||
| dst_interface = inet_name[vm_src] | ||||||||||||||||||||||
| else: | ||||||||||||||||||||||
| dst_interface = host_ifname | ||||||||||||||||||||||
|
Comment on lines
+126
to
+129
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Fix interface selection logic for guest-to-guest transfer. When Apply this diff: if params.get_boolean("using_guest_interface"):
- dst_interface = inet_name[vm_src]
+ dst_interface = inet_name[vm_dst]
else:
dst_interface = host_ifname📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||||
| remote.scp_between_remotes( | ||||||||||||||||||||||
| addresses[vm_src], | ||||||||||||||||||||||
| addresses[vm_dst], | ||||||||||||||||||||||
| port, | ||||||||||||||||||||||
| password, | ||||||||||||||||||||||
| password, | ||||||||||||||||||||||
| username, | ||||||||||||||||||||||
| username, | ||||||||||||||||||||||
| guest_path, | ||||||||||||||||||||||
| dest_path, | ||||||||||||||||||||||
| timeout=file_trans_timeout, | ||||||||||||||||||||||
| src_inter=host_ifname, | ||||||||||||||||||||||
| dst_inter=dst_interface, | ||||||||||||||||||||||
| ) | ||||||||||||||||||||||
| dst_md5 = get_file_md5sum( | ||||||||||||||||||||||
| dest_path, sessions[vm_dst], timeout=file_md5_check_timeout | ||||||||||||||||||||||
| ) | ||||||||||||||||||||||
| error_context.context( | ||||||||||||||||||||||
| "md5 value of data in %s: %s" % (vm.name, dst_md5), | ||||||||||||||||||||||
| test.log.info, | ||||||||||||||||||||||
| ) | ||||||||||||||||||||||
|
Comment on lines
+147
to
+150
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Fix incorrect variable reference in error context. Line 148 uses Apply this diff: dst_md5 = get_file_md5sum(
dest_path, sessions[vm_dst], timeout=file_md5_check_timeout
)
error_context.context(
- "md5 value of data in %s: %s" % (vm.name, dst_md5),
+ "md5 value of data in %s: %s" % (vm_dst.name, dst_md5),
test.log.info,
)📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||||
| if dst_md5 != src_md5: | ||||||||||||||||||||||
| test.fail( | ||||||||||||||||||||||
| "File changed transfer %s -> %s" | ||||||||||||||||||||||
| % (vm_src.name, vm_dst.name) | ||||||||||||||||||||||
| ) | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| for vm in vms: | ||||||||||||||||||||||
| error_context.context( | ||||||||||||||||||||||
| "Transfer data from %s to host" % vm.name, test.log.info | ||||||||||||||||||||||
| ) | ||||||||||||||||||||||
| remote.copy_files_from( | ||||||||||||||||||||||
| addresses[vm], | ||||||||||||||||||||||
| client, | ||||||||||||||||||||||
| username, | ||||||||||||||||||||||
| password, | ||||||||||||||||||||||
| port, | ||||||||||||||||||||||
| guest_path, | ||||||||||||||||||||||
| host_path, | ||||||||||||||||||||||
| timeout=file_trans_timeout, | ||||||||||||||||||||||
| interface=host_ifname, | ||||||||||||||||||||||
| ) | ||||||||||||||||||||||
| error_context.context( | ||||||||||||||||||||||
| "Check whether the file changed after trans", test.log.info | ||||||||||||||||||||||
| ) | ||||||||||||||||||||||
| dst_md5 = crypto.hash_file(host_path, algorithm="md5") | ||||||||||||||||||||||
| error_context.context( | ||||||||||||||||||||||
| "md5 value of data after copying to host: %s" % dst_md5, test.log.info | ||||||||||||||||||||||
| ) | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| if dst_md5 != src_md5: | ||||||||||||||||||||||
| test.fail("File changed after transfer (md5sum mismatch)") | ||||||||||||||||||||||
| process.system_output("rm -rf %s" % host_path, timeout=timeout) | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| finally: | ||||||||||||||||||||||
| process.system("rm -rf %s" % host_path, timeout=timeout, ignore_status=True) | ||||||||||||||||||||||
| for vm in vms: | ||||||||||||||||||||||
| if params.get("os_type") == "linux": | ||||||||||||||||||||||
| sessions[vm].cmd( | ||||||||||||||||||||||
| "rm -rf %s %s || true" % (guest_path, dest_path), | ||||||||||||||||||||||
| timeout=timeout, | ||||||||||||||||||||||
| ignore_all_errors=True, | ||||||||||||||||||||||
| ) | ||||||||||||||||||||||
| else: | ||||||||||||||||||||||
| sessions[vm].cmd( | ||||||||||||||||||||||
| "del /f %s" % guest_path, timeout=timeout, ignore_all_errors=True | ||||||||||||||||||||||
| ) | ||||||||||||||||||||||
| sessions[vm].close() | ||||||||||||||||||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧩 Analysis chain
Verify Windows path escaping.
The Windows temporary directory path uses a single backslash. Depending on how the configuration parser handles this string, it may need to be escaped as
C:\\\\or use a raw string format.Run the following script to check how similar Windows paths are defined in other test configurations:
🏁 Script executed:
Length of output: 27
🏁 Script executed:
Length of output: 47424
🏁 Script executed:
Length of output: 18756
🏁 Script executed:
Length of output: 2627
🏁 Script executed:
Length of output: 143
🌐 Web query:
💡 Result:
Short summary — rules for backslash and double quotes in YAML strings:
Single-quoted scalars: backslash has no special meaning (it is a literal character). The only escape is to double a single quote: 'He''s'. Use single quotes when you want literal backslashes. (yaml.info)
Double-quoted scalars: backslash introduces escape sequences (JSON/C-like). You must escape the double-quote (") and the backslash (\). Supported escapes include common ones (\n, \t, \r, \b, \f, \a, \0), hex/unicode (\xNN, \uNNNN, \UNNNNNNNN), and special YAML escapes; an escaped line break is ignored (allows multiline). Invalid escape sequences are an error. Examples:
References:
If you want, I can list the full escape sequence table from the spec or give parser-specific notes (some YAML parsers differ slightly).
Citations:
🏁 Script executed:
Length of output: 9908
Fix Windows tmp_dir path escaping from
"C:\\"to"C:\\\\"In the configuration file, the Windows tmp_dir path uses insufficient escaping for YAML double-quoted strings. In YAML double-quoted strings, backslash introduces escape sequences, and the backslash itself must be escaped as
\\.The current value
"C:\\"is parsed asC:\(single backslash). When concatenated with filenames in the test code (line 81-82 oftransfer_file_over_ipv6.py), this produces invalid paths likeC:\src-xxx.To produce the correct path separator, use
"C:\\\\"which parses toC:\\(double backslash), resulting in valid concatenated paths likeC:\\src-xxx.🤖 Prompt for AI Agents