def run(test, params, env): """ Test guestinfo command, make sure that all supported options work well """ def check_guest_os_info(): os_info = {} session = vm.wait_for_login() try: output = session.cmd_output( 'cat /etc/os-release').strip().splitlines() os_info_dict = dict(item.split("=") for item in output if item) os_info["os.id"] = os_info_dict["ID"].strip('"') os_info["os.name"] = os_info_dict["NAME"].strip('"') os_info["os.pretty-name"] = os_info_dict["PRETTY_NAME"].strip('"') os_info["os.version"] = os_info_dict["VERSION"].strip('"') os_info["os.version-id"] = os_info_dict["VERSION_ID"].strip('"') os_info["os.machine"] = session.cmd_output('uname -m').strip() os_info["os.kernel-release"] = session.cmd_output( 'uname -r').strip() os_info["os.kernel-version"] = session.cmd_output( 'uname -v').strip() finally: session.close() return os_info def parse_timezone_info(): session = vm.wait_for_login() try: output = session.cmd_output('timedatectl').strip().splitlines() out_dict = dict(item.split(": ") for item in output if item) tz_dict = dict((x.strip(), y.strip()) for x, y in out_dict.items()) tz_info = re.search(r"\((.+)\)", tz_dict["Time zone"]).group(1) name, offset = tz_info.split(', ') finally: session.close() return name, offset def check_guest_timezone_info(): timezone_info = {} timezone_name, hour_offset = parse_timezone_info() timezone_info["timezone.name"] = timezone_name sign = 1 if int(hour_offset) > 0 else -1 second_offset = int(hour_offset[-4:-2]) * 3600 + int( hour_offset[-2:] * 60) timezone_info["timezone.offset"] = str(sign * second_offset) return timezone_info def check_guest_hostname_info(): hostname_info = {} session = vm.wait_for_login() try: hostname_info['hostname'] = session.cmd_output('hostname').strip() finally: session.close() return hostname_info def add_user(name, passwd): session = vm.wait_for_login() try: session.cmd_output('useradd %s' % name) logging.debug('now system users are %s', session.cmd_output('users')) finally: session.close() virsh.set_user_password(vm_name, name, passwd, debug=True) def convert_to_timestamp(t_str): dt = dateutil.parser.parse(t_str) timestamp = datetime.datetime.timestamp(dt) return timestamp def check_guest_user_info(): user_info = {} session = vm.wait_for_login() try: output = session.cmd_output( 'last --time-format iso').strip().splitlines() users_login = [ item for item in output if re.search(r'still logged in', item) ] users_login_list = [ re.split(r"\s{2,}", item) for item in users_login ] users_login_info = [[item[0], convert_to_timestamp(item[-2])] for item in users_login_list] sorted_user_info = sorted(users_login_info, key=lambda item: item[1]) count = -1 users_list = [] for user, login_time in sorted_user_info: if user not in users_list: users_list.append(user) count += 1 user_key = "user." + str(count) + ".name" login_time_key = "user." + str(count) + ".login-time" user_info[user_key] = user user_info[login_time_key] = login_time finally: session.close() return len(users_list), user_info def check_disk_size(ses, disk): disk_size = ses.cmd_output('df %s' % disk).strip().splitlines()[-1] total_size = disk_size.split()[1] used_size = disk_size.split()[2] return total_size, used_size def check_guest_filesystem_info(): fs_info = {} count = -1 session = vm.wait_for_login() try: lsblk_cmd = 'lsblk -Jp -o KNAME,FSTYPE,TYPE,MOUNTPOINT,PKNAME,SERIAL' output = json.loads(session.cmd_output(lsblk_cmd).strip()) fs_unsorted = [ item for item in dict(output)['blockdevices'] if item['mountpoint'] not in [None, '[SWAP]'] ] fs = sorted(fs_unsorted, key=lambda item: item['kname']) fs_info['fs.count'] = str(len(fs)) for item in fs: total_size, used_size = check_disk_size(session, item['kname']) count += 1 key_prefix = 'fs.' + str(count) + '.' fs_info[key_prefix + 'name'] = os.path.basename(item['kname']) fs_info[key_prefix + 'mountpoint'] = item['mountpoint'] fs_info[key_prefix + 'fstype'] = item['fstype'] fs_info[key_prefix + 'total-bytes'] = str( int(total_size) * 1024) fs_info[key_prefix + 'used-bytes'] = str(int(used_size) * 1024) disks_count = item['pkname'].count('/dev') fs_info[key_prefix + 'disk.count'] = str(disks_count) for i in range(disks_count): fs_info[key_prefix + "disk." + str(i) + ".alias"] = re.search( r"(\D+)", os.path.basename(item['pkname'])).group(0) if item['serial']: fs_info[key_prefix + "disk." + str(i) + ".serial"] = item['serial'] if item['type'] == "lvm": fs_info[key_prefix + "disk." + str(i) + ".device"] = item['pkname'] else: fs_info[key_prefix + "disk." + str(i) + ".device"] = item['kname'] finally: session.close() return fs_info vm_name = params.get("main_vm") option = params.get("option") added_user_name = params.get("added_user_name") added_user_passwd = params.get("added_user_passwd") status_error = ("yes" == params.get("status_error", "no")) start_ga = ("yes" == params.get("start_ga", "yes")) prepare_channel = ("yes" == params.get("prepare_channel", "yes")) if not libvirt_version.version_compare(6, 0, 0): test.cancel( "Guestinfo command is not supported before version libvirt-6.0.0 ") import dateutil.parser try: vm = env.get_vm(vm_name) if start_ga and prepare_channel: vm.prepare_guest_agent(start=True, channel=True) if "user" in option: add_user(added_user_name, added_user_passwd) added_user_session = vm.wait_for_login(username=added_user_name, password=added_user_passwd) root_session = vm.wait_for_login() result = virsh.guestinfo(vm_name, option, ignore_status=True, debug=True) libvirt.check_exit_status(result, status_error) out = result.stdout.strip().splitlines() out_dict = dict(item.split(" : ") for item in out) info_from_agent_cmd = dict( (x.strip(), y.strip()) for x, y in out_dict.items()) logging.debug("info from the guest is %s", info_from_agent_cmd) func_name = "check_guest_%s_info" % option[2:] if "user" not in option: info_from_guest = locals()[func_name]() logging.debug('%s_info_from_guest is %s', option[2:], info_from_guest) if info_from_guest != info_from_agent_cmd: test.fail( "The %s info get from guestinfo cmd is not correct." % option[2:]) else: user_count, user_info_from_guest = check_guest_user_info() if user_count != int(info_from_agent_cmd["user.count"]): test.fail("The num of active users returned from guestinfo " "is not correct.") for key, value in user_info_from_guest.items(): # login time returned from guestinfo cmd is with milliseconds, # so it may cause at most 1 second deviation if "name" in key: if value != info_from_agent_cmd[key]: test.fail("The active users get from guestinfo " "are not correct.") if "login-time" in key: if abs( float(value) - int(info_from_agent_cmd[key]) / 1000) > 1.0: test.fail( "The login time of active users get from guestinfo " "is not correct.") finally: if "user" in option: added_user_session.close() root_session.cmd('userdel -f %s' % added_user_name) root_session.close() vm.destroy()
def run(test, params, env): """ Test guestinfo command, make sure that all supported options work well """ def hotplug_disk(disk_name): """ hotplug a disk to guest :param disk_name: the name of the disk be hotplugged """ device_source = os.path.join(data_dir.get_tmp_dir(), disk_name) libvirt.create_local_disk("file", device_source, size='1') try: res = virsh.attach_disk(vm_name, device_source, disk_target_name, debug=True) utils_misc.wait_for(lambda: (res.stdout == "Disk attached successfully"), 10) except Exception: test.error("Can not attach %s to the guest" % disk_target_name) def check_attached_disk_info(disk_info, target_name): """ Check the info of the attached disk :param disk_info: the disk info returned from virsh guestinfo --disk :param target_name: the target name for the attached disk :return: the attached disk info returned from virsh guestinfo --disk """ attached_disk_info_reported = False disk_logical_name = '/dev/%s' % target_name for i in range(int(disk_info['disk.count'])): prefix = 'disk.' + str(i) + '.' try: if disk_info[prefix + 'alias'] == target_name: if (disk_info[prefix + 'name'] == disk_logical_name and disk_info[prefix + 'partition'] == 'no'): attached_disk_info_reported = True break except KeyError: logging.error("Num %i is not the attached disk", i) return attached_disk_info_reported def check_guest_os_info(): """ Check the info of guest os from guest side :return: the guest os info from guest side """ os_info = {} session = vm.wait_for_login() try: output = session.cmd_output('cat /etc/os-release').strip().splitlines() os_info_dict = dict(item.split("=") for item in output if item) os_info["os.id"] = os_info_dict["ID"].strip('"') os_info["os.name"] = os_info_dict["NAME"].strip('"') os_info["os.pretty-name"] = os_info_dict["PRETTY_NAME"].strip('"') os_info["os.version"] = os_info_dict["VERSION"].strip('"') os_info["os.version-id"] = os_info_dict["VERSION_ID"].strip('"') os_info["os.machine"] = session.cmd_output('uname -m').strip() os_info["os.kernel-release"] = session.cmd_output('uname -r').strip() os_info["os.kernel-version"] = session.cmd_output('uname -v').strip() finally: session.close() return os_info def parse_timezone_info(): """ Parse the info returned from timedatectl cmd :return: the guest timezone name and offset to UTC time """ session = vm.wait_for_login() try: output = session.cmd_output('timedatectl').strip().splitlines() out_dict = dict(item.split(": ") for item in output if item) tz_dict = dict((x.strip(), y.strip()) for x, y in out_dict.items()) tz_info = re.search(r"\((.+)\)", tz_dict["Time zone"]).group(1) name, offset = tz_info.split(', ') finally: session.close() return name, offset def check_guest_timezone_info(): """ Check the info of guest timezone from guest side :return: the guest timezone info from guest side """ timezone_info = {} timezone_name, hour_offset = parse_timezone_info() timezone_info["timezone.name"] = timezone_name sign = 1 if int(hour_offset) > 0 else -1 second_offset = int(hour_offset[-4:-2])*3600 + int(hour_offset[-2:]*60) timezone_info["timezone.offset"] = str(sign * second_offset) return timezone_info def check_guest_hostname_info(): """ Check the info of guest hostname from guest side :return: the guest hostname info from guest side """ hostname_info = {} session = vm.wait_for_login() try: output = session.cmd_output('hostname').strip() if not output: output = session.cmd_output('hostnamectl --static').strip() if not output: output = session.cmd_output('hostnamectl --transient').strip() finally: session.close() hostname_info['hostname'] = output return hostname_info def add_user(name, passwd): """ Added a user account :param name: user name :param passwd: password of user account """ session = vm.wait_for_login() try: session.cmd_output('useradd %s' % name) logging.debug('now system users are %s', session.cmd_output('users')) finally: session.close() virsh.set_user_password(vm_name, name, passwd, debug=True) def convert_to_timestamp(t_str): dt = dateutil.parser.parse(t_str) timestamp = datetime.datetime.timestamp(dt) return timestamp def check_guest_user_info(): """ check the info of guest user from guest side :return: the guest user info from guest side """ user_info = {} session = vm.wait_for_login() try: output = session.cmd_output('last --time-format iso').strip().splitlines() users_login = [item for item in output if re.search(r'still logged in', item)] users_login_list = [re.split(r"\s{2,}", item) for item in users_login] users_login_info = [[item[0], convert_to_timestamp(item[-2])] for item in users_login_list] sorted_user_info = sorted(users_login_info, key=lambda item: item[1]) count = -1 users_list = [] for user, login_time in sorted_user_info: if user not in users_list: users_list.append(user) count += 1 user_key = "user." + str(count) + ".name" login_time_key = "user." + str(count) + ".login-time" user_info[user_key] = user user_info[login_time_key] = login_time user_info["user.count"] = str(len(users_list)) finally: session.close() return user_info def check_disk_size(ses, disk): """ check the disk size from guest side :return: total size and used size of the disk """ disk_size = ses.cmd_output('df %s' % disk).strip().splitlines()[-1] total_size = disk_size.split()[1] used_size = disk_size.split()[2] return total_size, used_size def check_guest_filesystem_info(info_from_agent_cmd): """ check the info of filesystem from guest side :param info_from_agent_cmd: fs info from agent cmd :return: the filesystem info from guest side """ fs_info = {} fs = [] count = -1 session = vm.wait_for_login() try: lsblk_cmd = 'lsblk -Jp -o KNAME,FSTYPE,TYPE,MOUNTPOINT,PKNAME,SERIAL' output = json.loads(session.cmd_output(lsblk_cmd).strip()) fs_unsorted = [item for item in dict(output)['blockdevices'] if item['mountpoint'] not in [None, '[SWAP]']] # Sort the guest disks that have fs to ensure the order is same # with agent cmd. # There is no order guarantee of fs. The output of guestinfo # filesystem is in the order whatever the agent reported by # parsing /proc/self/mountinfo. disk_from_agent = [v for k, v in info_from_agent_cmd.items() if "name" in k] logging.debug("disk_from_agent is %s" % disk_from_agent) # Sort the guest filesystem in the order of agent output for disk in disk_from_agent: for item in fs_unsorted: if disk in item['kname']: fs.append(item) fs_unsorted.remove(item) fs.extend(fs_unsorted) logging.debug("fs is %s" % fs) fs_info['fs.count'] = str(len(fs)) for item in fs: total_size, used_size = check_disk_size(session, item['kname']) count += 1 key_prefix = 'fs.' + str(count) + '.' fs_info[key_prefix + 'name'] = os.path.basename(item['kname']) fs_info[key_prefix + 'mountpoint'] = item['mountpoint'] fs_info[key_prefix + 'fstype'] = item['fstype'] fs_info[key_prefix + 'total-bytes'] = str(int(total_size)*1024) fs_info[key_prefix + 'used-bytes'] = str(int(used_size)*1024) disks_count = item['pkname'].count('/dev') fs_info[key_prefix + 'disk.count'] = str(disks_count) for i in range(disks_count): fs_info[key_prefix + "disk." + str(i) + ".alias"] = re.search( r"(\D+)", os.path.basename(item['pkname'])).group(0) if item['serial']: fs_info[key_prefix + "disk." + str(i) + ".serial"] = item['serial'] if item['type'] == "lvm": fs_info[key_prefix + "disk." + str(i) + ".device"] = item['pkname'] else: fs_info[key_prefix + "disk." + str(i) + ".device"] = item['kname'] finally: session.close() return fs_info vm_name = params.get("main_vm") option = params.get("option", " ") added_user_name = params.get("added_user_name") added_user_passwd = params.get("added_user_passwd") status_error = ("yes" == params.get("status_error", "no")) start_ga = ("yes" == params.get("start_ga", "yes")) prepare_channel = ("yes" == params.get("prepare_channel", "yes")) disk_target_name = params.get("disk_target_name") disk_name = params.get("disk_name") readonly_mode = ("yes" == params.get("readonly_mode")) if not libvirt_version.version_compare(6, 0, 0): test.cancel("Guestinfo command is not supported before version libvirt-6.0.0 ") import dateutil.parser added_user_session = None root_session = None try: vm = env.get_vm(vm_name) virsh_dargs = {} if readonly_mode: virsh_dargs["readonly"] = True if start_ga and prepare_channel: vm.prepare_guest_agent(start=True, channel=True) if "user" in option: add_user(added_user_name, added_user_passwd) added_user_session = vm.wait_for_login(username=added_user_name, password=added_user_passwd) root_session = vm.wait_for_login() if "disk" in option: hotplug_disk(disk_name) result = virsh.guestinfo(vm_name, option, **virsh_dargs, ignore_status=True, debug=True) error_msg = [] if not prepare_channel: error_msg.append("QEMU guest agent is not configured") if readonly_mode: error_msg.append("read only access prevents virDomainGetGuestInfo") libvirt.check_result(result, expected_fails=error_msg, any_error=status_error) if status_error: return out = result.stdout.strip().splitlines() out_dict = dict(item.split(": ") for item in out) info_from_agent_cmd = dict((x.strip(), y.strip()) for x, y in out_dict.items()) logging.debug("info from the guest is %s", info_from_agent_cmd) if "disk" in option: if not check_attached_disk_info(info_from_agent_cmd, disk_target_name): test.fail("The disk info reported by agent cmd is not correct. " "result: %s" % info_from_agent_cmd) return else: if "filesystem" in option: info_from_guest = check_guest_filesystem_info(info_from_agent_cmd) else: func_name = "check_guest_%s_info" % option[2:] info_from_guest = locals()[func_name]() logging.debug('%s_info_from_guest is %s', option[2:], info_from_guest) if ("user" not in option) and ("filesystem" not in option): if info_from_guest != info_from_agent_cmd: test.fail("The %s info get from guestinfo cmd is not correct." % option[2:]) else: for key, value in info_from_guest.items(): if "used-bytes" in key: # The guest block size may change by about 16000Kib after # getting info via guestinfo cmd. We just need make sure # the size difference will not exceed then 17000KiB. if abs(int(value) - int(info_from_agent_cmd[key])) > 17408000: test.fail("The block size returned from guest agent " "is not correct.") elif "login-time" in key: # login time returned from guestinfo cmd is with milliseconds, # so it may cause at most 1 second deviation if abs(float(value) - int(info_from_agent_cmd[key])/1000) > 1.0: test.fail("The login time of active users get from guestinfo " "is not correct.") else: if value != info_from_agent_cmd[key]: test.fail("The %s info get from guestinfo cmd" "is not correct." % option[2:]) finally: if "user" in option: if added_user_session: added_user_session.close() if root_session: root_session.cmd('userdel -f %s' % added_user_name) root_session.close() if "disk" in option: virsh.detach_disk(vm_name, disk_target_name, ignore_status=False, debug=True) vm.destroy()