def get_parameter_in_cgroup(vm, cgroup_type, parameter): """ Get vm's cgroup value. :Param vm: the vm object :Param cgroup_type: type of cgroup we want, vcpu or emulator. :Param parameter: the cgroup parameter of vm which we need to get. :return: False if expected controller is not mounted. else return value's result object. """ cgroup_path = \ utils_cgroup.resolve_task_cgroup_path(vm.get_pid(), "cpu") if not cgroup_type == "emulator": # When a VM has an 'emulator' child cgroup present, we must # strip off that suffix when detecting the cgroup for a machine if os.path.basename(cgroup_path) == "emulator": cgroup_path = os.path.dirname(cgroup_path) cgroup_file = os.path.join(cgroup_path, parameter) else: cgroup_file = os.path.join(cgroup_path, parameter) cg_file = None try: try: cg_file = open(cgroup_file) result = cg_file.read() except IOError: raise error.TestError("Failed to open cgroup file %s" % cgroup_file) finally: if cg_file is not None: cg_file.close() return result.strip()
def get_cgroup_path(self, controller=None): """ Get specific cgroup controller's root path :params controller: The cgroup controller, used for cgroup v1. For cgroup v2 this param will be ignored since all controllers are in the same dir :return: The path to the cgroup controller """ cgroup_path = "" if self.is_cgroup_v2_enabled(): vm_proc_cgroup_path = "/proc/%s/cgroup" % self.__vm_pid with open('/proc/mounts', 'r') as mnts: cg_mount_point = re.findall(r"\s(\S*cgroup)\s", mnts.read()) with open(vm_proc_cgroup_path, 'r') as vm_cg_file: cg_vm_scope = re.findall(r"\S*::(\S*)", vm_cg_file.read()) cgroup_path = os.path.join(cg_mount_point[0], cg_vm_scope[0].strip("/")) if "emulator" in cgroup_path: cgroup_path += "/.." else: cgroup_path = utils_cgroup.resolve_task_cgroup_path( int(self.__vm_pid), controller) if not os.path.exists(cgroup_path): logging.error("cgroup path '%s' doesn't exist" % cgroup_path) return None return cgroup_path
def get_parameter_in_cgroup(vm, parameter): """ Get vm's cgroup value. @Param vm: the vm object @Param parameter: the cgroup parameter of vm which we need to get. :return: False if expected controller is not mounted. else return value's result object. """ cgroup_path = \ utils_cgroup.resolve_task_cgroup_path(vm.get_pid(), "cpu") cgroup_file = os.path.join(cgroup_path, parameter) if not os.path.exists(cgroup_file): raise error.TestNAError("Unknown path to cgroups", cgroup_file) get_value_cmd = "cat %s" % cgroup_file result = utils.run(get_value_cmd, ignore_status=True) return result.stdout.strip()
def get_emulatorpin_from_cgroup(params, test): """ Get a list of domain-specific per block stats from cgroup blkio controller. :params: the parameter dictionary """ vm = params.get("vm") cpuset_path = \ utils_cgroup.resolve_task_cgroup_path(vm.get_pid(), "cpuset") cpuset_file = os.path.join(cpuset_path, "cpuset.cpus") try: with open(cpuset_file, "rU") as f_emulatorpin_params: emulatorpin_params_from_cgroup = f_emulatorpin_params.readline() return emulatorpin_params_from_cgroup except IOError: test.error("Failed to get emulatorpin " "params from %s" % cpuset_file)
def get_parameter_in_cgroup(vm, cgroup_type, parameter): """ Get vm's cgroup value. :Param vm: the vm object :Param cgroup_type: type of cgroup we want, vcpu or emulator. :Param parameter: the cgroup parameter of vm which we need to get. :return: False if expected controller is not mounted. else return value's result object. """ cgroup_path = \ utils_cgroup.resolve_task_cgroup_path(vm.get_pid(), "cpu") logging.debug("cgroup_path=%s", cgroup_path) if not cgroup_type == "emulator": # When a VM has an 'emulator' child cgroup present, we must # strip off that suffix when detecting the cgroup for a machine if os.path.basename(cgroup_path) == "emulator": cgroup_path = os.path.dirname(cgroup_path) if cgroup_type == 'iothread': parameter = 'iothread1/%s' % parameter if cgroup_type == 'vcpu' and parameter != 'cpu.shares': parameter = 'vcpu0/%s' % parameter if parameter == 'cpu.shares' and libvirt_version.version_compare( 7, 0, 0): cgroup_path = os.path.dirname(cgroup_path) logging.debug("cgroup_path is updated to '%s'", cgroup_path) cgroup_file = os.path.join(cgroup_path, parameter) logging.debug("cgroup_file=%s", cgroup_file) cg_file = None try: try: cg_file = open(cgroup_file) result = cg_file.read() except IOError: test.error("Failed to open cgroup file %s" % cgroup_file) finally: if cg_file is not None: cg_file.close() return result.strip()
def run(test, params, env): """ Test virsh cpu-stats command. The command can display domain per-CPU and total statistics. 1. Call virsh cpu-stats [domain] 2. Call virsh cpu-stats [domain] with valid options 3. Call virsh cpu-stats [domain] with invalide options """ if not virsh.has_help_command('cpu-stats'): raise error.TestNAError("This version of libvirt does not support " "the cpu-stats test") vm_name = params.get("main_vm", "vm1") vm_ref = params.get("cpu_stats_vm_ref") status_error = params.get("status_error", "no") options = params.get("cpu_stats_options") logging.debug("options are %s", options) if vm_ref == "name": vm_ref = vm_name # get host cpus num cpus = multiprocessing.cpu_count() logging.debug("host cpu num is %s", cpus) # get options and put into a dict get_total = re.search('total', options) get_start = re.search('start', options) get_count = re.search('count', options) # command without options get_noopt = 0 if not get_total and not get_start and not get_count: get_noopt = 1 # command with only --total option get_totalonly = 0 if not get_start and not get_count and get_total: get_totalonly = 1 option_dict = {} if options.strip(): option_list = options.split('--') logging.debug("option_list is %s", option_list) for match in option_list[1:]: if get_start or get_count: option_dict[match.split(' ')[0]] = match.split(' ')[1] # Run virsh command cmd_result = virsh.cpu_stats(vm_ref, options, ignore_status=True, debug=True) output = cmd_result.stdout.strip() status = cmd_result.exit_status # check status_error if status_error == "yes": if status == 0: raise error.TestFail("Run successfully with wrong command!") elif status_error == "no": if status != 0: raise error.TestFail("Run failed with right command") else: # Get cgroup cpu_time if not get_totalonly: vm = env.get_vm(vm_ref) cgpath = utils_cgroup.resolve_task_cgroup_path( vm.get_pid(), "cpuacct") # When a VM has an 'emulator' child cgroup present, we must # strip off that suffix when detecting the cgroup for a machine if os.path.basename(cgpath) == "emulator": cgpath = os.path.dirname(cgpath) usage_file = os.path.join(cgpath, "cpuacct.usage_percpu") cgtime = file(usage_file).read().strip().split() logging.debug("cgtime get is %s", cgtime) # Cut CPUs from output and format to list output = re.sub(r'\.', '', output) if get_total: mt_start = re.search('Total', output).start() else: mt_start = len(output) output_cpus = " ".join(output[:mt_start].split()) cpus_list = re.compile(r'CPU\d+:').split(output_cpus) # conditions that list total time info if get_noopt or get_total: mt_end = re.search('Total', output).end() total_list = output[mt_end + 1:].split() total_time = int(total_list[1]) user_time = int(total_list[4]) system_time = int(total_list[7]) # check Total cpu_time >= User + System cpu_time if user_time + system_time >= total_time: raise error.TestFail("total cpu_time < user_time + " "system_time") logging.debug("Check total cpu_time %d >= user + system " "cpu_time %d", total_time, user_time + system_time) start_num = 0 if get_start: start_num = int(option_dict["start"]) end_num = int(cpus) if get_count: count_num = int(option_dict["count"]) if end_num > start_num + count_num: end_num = start_num + count_num # for only give --total option it only shows "Total" cpu info if get_totalonly: end_num = -1 # find CPU[N] in output and sum the cpu_time and cgroup cpu_time sum_cputime = 0 sum_cgtime = 0 logging.debug("start_num %d, end_num %d", start_num, end_num) for i in range(start_num, end_num): if not re.search('CPU' + "%i" % i, output): raise error.TestFail("Fail to find CPU" + "%i" % i + "in " "result") logging.debug("Check CPU" + "%i" % i + " exist") sum_cputime += int(cpus_list[i - start_num + 1].split()[1]) sum_cgtime += int(cgtime[i]) # check cgroup cpu_time > sum of cpu_time if end_num >= 0: if sum_cputime > sum_cgtime: raise error.TestFail("Check sum of cgroup cpu_time < sum " "of output cpu_time") logging.debug("Check sum of cgroup cpu_time %d >= cpu_time %d", sum_cgtime, sum_cputime) # check Total cpu_time >= sum of cpu_time when no options if get_noopt: if total_time < sum_cputime: raise error.TestFail("total time < sum of output cpu_time") logging.debug("Check total time %d >= sum of output cpu_time" " %d", total_time, sum_cputime)
def run(test, params, env): """ Test the command virsh memtune (1) To get the current memtune parameters (2) Change the parameter values (3) Check the memtune query updated with the values (4) Check whether the mounted cgroup path gets the updated value (5) Login to guest and use the memory greater that the assigned value and check whether it kills the vm. (6) TODO:Check more values and robust scenarios. """ def check_limit(path, expected_value, limit_name): """ Matches the expected and actual output (1) Match the output of the virsh memtune (2) Match the output of the respective cgroup fs value :params: path: memory controller path for a domain :params: expected_value: the expected limit value :params: limit_name: the limit to be checked hard_limit/soft_limit/swap_hard_limit :return: True or False based on the checks """ status_value = True # Check 1 actual_value = virsh.memtune_get(domname, limit_name) if actual_value == -1: raise error.TestFail("the key %s not found in the " "virsh memtune output" % limit_name) if actual_value != int(expected_value): status_value = False logging.error("%s virsh output:\n\tExpected value:%d" "\n\tActual value: " "%d", limit_name, int(expected_value), int(actual_value)) # Check 2 if limit_name == 'hard_limit': cg_file_name = '%s/memory.limit_in_bytes' % path elif limit_name == 'soft_limit': cg_file_name = '%s/memory.soft_limit_in_bytes' % path elif limit_name == 'swap_hard_limit': cg_file_name = '%s/memory.memsw.limit_in_bytes' % path cg_file = None try: try: cg_file = open(cg_file_name) output = cg_file.read() value = int(output) / 1024 if int(expected_value) != int(value): status_value = False logging.error("%s cgroup fs:\n\tExpected Value: %d" "\n\tActual Value: " "%d", limit_name, int(expected_value), int(value)) except IOError: status_value = False logging.error("Error while reading:\n%s", cg_file_name) finally: if cg_file is not None: cg_file.close() return status_value # Get the vm name, pid of vm and check for alive domname = params.get("main_vm") vm = env.get_vm(params["main_vm"]) vm.verify_alive() pid = vm.get_pid() logging.info("Verify valid cgroup path for VM pid: %s", pid) # Resolve the memory cgroup path for a domain path = utils_cgroup.resolve_task_cgroup_path(int(pid), "memory") # Set the initial memory starting value for test case # By default set 1GB less than the total memory # In case of total memory is less than 1GB set to 256MB # visit subtests.cfg to change these default values Memtotal = utils_memory.read_from_meminfo('MemTotal') base_mem = params.get("memtune_base_mem") if int(Memtotal) < int(base_mem): Mem = int(params.get("memtune_min_mem")) else: Mem = int(Memtotal) - int(base_mem) # Initialize error counter error_counter = 0 # Check for memtune command is available in the libvirt version under test if not virsh.has_help_command("memtune"): raise error.TestNAError( "Memtune not available in this libvirt version") # Run test case with 100kB increase in memory value for each iteration while (Mem < Memtotal): if virsh.has_command_help_match("memtune", "hard-limit"): hard_mem = Mem - int(params.get("memtune_hard_base_mem")) options = " --hard-limit %d --live" % hard_mem virsh.memtune_set(domname, options) if not check_limit(path, hard_mem, "hard_limit"): error_counter += 1 else: raise error.TestNAError("harlimit option not available in memtune " "cmd in this libvirt version") if virsh.has_command_help_match("memtune", "soft-limit"): soft_mem = Mem - int(params.get("memtune_soft_base_mem")) options = " --soft-limit %d --live" % soft_mem virsh.memtune_set(domname, options) if not check_limit(path, soft_mem, "soft_limit"): error_counter += 1 else: raise error.TestNAError("softlimit option not available in memtune " "cmd in this libvirt version") if virsh.has_command_help_match("memtune", "swap-hard-limit"): swaphard = Mem options = " --swap-hard-limit %d --live" % swaphard virsh.memtune_set(domname, options) if not check_limit(path, swaphard, "swap_hard_limit"): error_counter += 1 else: raise error.TestNAError("swaplimit option not available in memtune " "cmd in this libvirt version") Mem += int(params.get("memtune_hard_base_mem")) # Raise error based on error_counter if error_counter > 0: raise error.TestFail( "Test failed, consult the previous error messages")
def run(test, params, env): """ Test the command virsh memtune 1) To get the current memtune parameters 2) Change the parameter values 3) Check the memtune query updated with the values 4) Check whether the mounted cgroup path gets the updated value 5) Check the output of virsh dumpxml 6) Check vm is alive """ # Check for memtune command is available in the libvirt version under test if not virsh.has_help_command("memtune"): test.cancel( "Memtune not available in this libvirt version") # Check if memtune options are supported for option in memtune_types: if not virsh.has_command_help_match("memtune", option): test.cancel("%s option not available in memtune " "cmd in this libvirt version" % option) # Get common parameters acceptable_minus = int(params.get("acceptable_minus", 8)) step_mem = params.get("mt_step_mem", "no") == "yes" expect_error = params.get("expect_error", "no") == "yes" restart_libvirtd = params.get("restart_libvirtd", "no") == "yes" set_one_line = params.get("set_in_one_command", "no") == "yes" mt_hard_limit = params.get("mt_hard_limit", None) mt_soft_limit = params.get("mt_soft_limit", None) mt_swap_hard_limit = params.get("mt_swap_hard_limit", None) # if restart_libvirtd is True, set set_one_line is True set_one_line = True if restart_libvirtd else set_one_line # Get the vm name, pid of vm and check for alive vm = env.get_vm(params["main_vm"]) vm.verify_alive() pid = vm.get_pid() # Resolve the memory cgroup path for a domain path = utils_cgroup.resolve_task_cgroup_path(int(pid), "memory") # step_mem is used to do step increment limit testing if step_mem: mem_step(params, path, vm, test, acceptable_minus) return if not set_one_line: # Set one type memtune limit in one command if mt_hard_limit: index = 0 mt_limit = mt_hard_limit elif mt_soft_limit: index = 1 mt_limit = mt_soft_limit elif mt_swap_hard_limit: index = 2 mt_limit = mt_swap_hard_limit mt_type = memtune_types[index] mt_cgname = memtune_cgnames[index] options = " --%s %s --live" % (mt_type, mt_limit) result = virsh.memtune_set(vm.name, options, debug=True) if expect_error: fail_patts = [params.get("error_info")] libvirt.check_result(result, fail_patts, []) else: # If limit value is negative, means no memtune limit mt_expected = mt_limit if int(mt_limit) > 0 else -1 check_limit(path, mt_expected, mt_type, mt_cgname, vm, test, acceptable_minus) else: # Set 3 limits in one command line mt_limits = [mt_hard_limit, mt_soft_limit, mt_swap_hard_limit] options = " %s --live" % ' '.join(mt_limits) result = virsh.memtune_set(vm.name, options, debug=True) if expect_error: fail_patts = [params.get("error_info")] libvirt.check_result(result, fail_patts, []) else: check_limits(path, mt_limits, vm, test, acceptable_minus) if restart_libvirtd: libvirtd = utils_libvirtd.Libvirtd() libvirtd.restart() if not expect_error: # After libvirtd restared, check memtune values again check_limits(path, mt_limits, vm, test, acceptable_minus)
def run(test, params, env): """ Test the command virsh memtune (1) To get the current memtune parameters (2) Change the parameter values (3) Check the memtune query updated with the values (4) Check whether the mounted cgroup path gets the updated value (5) Login to guest and use the memory greater that the assigned value and check whether it kills the vm. (6) TODO:Check more values and robust scenarios. """ def check_limit(path, expected_value, limit_name): """ Matches the expected and actual output (1) Match the output of the virsh memtune (2) Match the output of the respective cgroup fs value :params: path: memory controller path for a domain :params: expected_value: the expected limit value :params: limit_name: the limit to be checked hard_limit/soft_limit/swap_hard_limit :return: True or False based on the checks """ status_value = True # Check 1 actual_value = virsh.memtune_get(domname, limit_name) if actual_value == -1: test.fail("the key %s not found in the " "virsh memtune output" % limit_name) if actual_value != int(expected_value): status_value = False logging.error( "%s virsh output:\n\tExpected value:%d" "\n\tActual value: " "%d", limit_name, int(expected_value), int(actual_value)) # Check 2 if limit_name == 'hard_limit': cg_file_name = '%s/memory.limit_in_bytes' % path elif limit_name == 'soft_limit': cg_file_name = '%s/memory.soft_limit_in_bytes' % path elif limit_name == 'swap_hard_limit': cg_file_name = '%s/memory.memsw.limit_in_bytes' % path cg_file = None try: with open(cg_file_name) as cg_file: output = cg_file.read() value = int(output) / 1024 if int(expected_value) != int(value): status_value = False logging.error( "%s cgroup fs:\n\tExpected Value: %d" "\n\tActual Value: " "%d", limit_name, int(expected_value), int(value)) except IOError: status_value = False logging.error("Error while reading:\n%s", cg_file_name) return status_value # Get the vm name, pid of vm and check for alive domname = params.get("main_vm") vm = env.get_vm(params["main_vm"]) vm.verify_alive() pid = vm.get_pid() logging.info("Verify valid cgroup path for VM pid: %s", pid) # Resolve the memory cgroup path for a domain path = utils_cgroup.resolve_task_cgroup_path(int(pid), "memory") # Set the initial memory starting value for test case # By default set 1GB less than the total memory # In case of total memory is less than 1GB set to 256MB # visit subtests.cfg to change these default values Memtotal = utils_memory.read_from_meminfo('MemTotal') base_mem = params.get("memtune_base_mem") if int(Memtotal) < int(base_mem): Mem = int(params.get("memtune_min_mem")) else: Mem = int(Memtotal) - int(base_mem) # Initialize error counter error_counter = 0 # Check for memtune command is available in the libvirt version under test if not virsh.has_help_command("memtune"): test.cancel("Memtune not available in this libvirt version") # Run test case with 100kB increase in memory value for each iteration while (Mem < Memtotal): if virsh.has_command_help_match("memtune", "hard-limit"): hard_mem = Mem - int(params.get("memtune_hard_base_mem")) options = " --hard-limit %d --live" % hard_mem virsh.memtune_set(domname, options) if not check_limit(path, hard_mem, "hard_limit"): error_counter += 1 else: test.cancel("harlimit option not available in memtune " "cmd in this libvirt version") if virsh.has_command_help_match("memtune", "soft-limit"): soft_mem = Mem - int(params.get("memtune_soft_base_mem")) options = " --soft-limit %d --live" % soft_mem virsh.memtune_set(domname, options) if not check_limit(path, soft_mem, "soft_limit"): error_counter += 1 else: test.cancel("softlimit option not available in memtune " "cmd in this libvirt version") if virsh.has_command_help_match("memtune", "swap-hard-limit"): swaphard = Mem options = " --swap-hard-limit %d --live" % swaphard virsh.memtune_set(domname, options) if not check_limit(path, swaphard, "swap_hard_limit"): error_counter += 1 else: test.cancel("swaplimit option not available in memtune " "cmd in this libvirt version") Mem += int(params.get("memtune_hard_base_mem")) # Raise error based on error_counter if error_counter > 0: test.fail("Test failed, consult the previous error messages")
def run(test, params, env): """ Test the command virsh memtune 1) To get the current memtune parameters 2) Change the parameter values 3) Check the memtune query updated with the values 4) Check whether the mounted cgroup path gets the updated value 5) Check the output of virsh dumpxml 6) Check vm is alive """ # Check for memtune command is available in the libvirt version under test if not virsh.has_help_command("memtune"): test.cancel("Memtune not available in this libvirt version") # Check if memtune options are supported for option in memtune_types: if not virsh.has_command_help_match("memtune", option): test.cancel("%s option not available in memtune " "cmd in this libvirt version" % option) # Get common parameters acceptable_minus = int(params.get("acceptable_minus", 8)) step_mem = params.get("mt_step_mem", "no") == "yes" expect_error = params.get("expect_error", "no") == "yes" restart_libvirtd = params.get("restart_libvirtd", "no") == "yes" set_one_line = params.get("set_in_one_command", "no") == "yes" mt_hard_limit = params.get("mt_hard_limit", None) mt_soft_limit = params.get("mt_soft_limit", None) mt_swap_hard_limit = params.get("mt_swap_hard_limit", None) # if restart_libvirtd is True, set set_one_line is True set_one_line = True if restart_libvirtd else set_one_line # Get the vm name, pid of vm and check for alive vm = env.get_vm(params["main_vm"]) vm.verify_alive() pid = vm.get_pid() # Resolve the memory cgroup path for a domain path = utils_cgroup.resolve_task_cgroup_path(int(pid), "memory") # step_mem is used to do step increment limit testing if step_mem: mem_step(params, path, vm, test, acceptable_minus) return if not set_one_line: # Set one type memtune limit in one command if mt_hard_limit: index = 0 mt_limit = mt_hard_limit elif mt_soft_limit: index = 1 mt_limit = mt_soft_limit elif mt_swap_hard_limit: index = 2 mt_limit = mt_swap_hard_limit mt_type = memtune_types[index] mt_cgname = memtune_cgnames[index] options = " --%s %s --live" % (mt_type, mt_limit) result = virsh.memtune_set(vm.name, options, debug=True) if expect_error: fail_patts = [params.get("error_info")] libvirt.check_result(result, fail_patts, []) else: # If limit value is negative, means no memtune limit mt_expected = mt_limit if int(mt_limit) > 0 else -1 check_limit(path, mt_expected, mt_type, mt_cgname, vm, test, acceptable_minus) else: # Set 3 limits in one command line mt_limits = [mt_hard_limit, mt_soft_limit, mt_swap_hard_limit] options = " %s --live" % ' '.join(mt_limits) result = virsh.memtune_set(vm.name, options, debug=True) if expect_error: fail_patts = [params.get("error_info")] libvirt.check_result(result, fail_patts, []) else: check_limits(path, mt_limits, vm, test, acceptable_minus) if restart_libvirtd: libvirtd = utils_libvirtd.Libvirtd() libvirtd.restart() if not expect_error: # After libvirtd restared, check memtune values again check_limits(path, mt_limits, vm, test, acceptable_minus)