swap-related units user input validation

This commit is contained in:
Alexey Avramov 2019-01-31 21:42:00 +09:00
parent 5cad925f5f
commit bd313a6952

172
nohang
View File

@ -40,27 +40,11 @@ HR = '~' * 79
print_total_stat = True print_total_stat = True
########################################################################## ##########################################################################
# define functions # define functions
def zenity():
# test
os.system('''sudo -u user DISPLAY=:0 DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/1000/bus zenity --checklist --timeout=10 --text="\n <b>Mem Available: 10% (300 MiB)</b>. \n\n Select a process to be terminated:\n" --ok-label "Terminate" --cancel-label "Do nothing" --separator=" " --width=9999 --height=9999 --list --title="Low memory!" --column "" --column="Pid" --column="Name" --column="VmRSS" 9923 9923 Python3 "800 MiB" 2938 2938 tail "400 MiB" 3938 3938 chromium "300 MiB"''')
# zenity()
def update_stat_dict_and_print(key): def update_stat_dict_and_print(key):
if key not in stat_dict: if key not in stat_dict:
@ -83,7 +67,6 @@ def update_stat_dict_and_print(key):
print(stats_msg) print(stats_msg)
def psi_mem_some_avg_total(): def psi_mem_some_avg_total():
if psi_support: if psi_support:
return float(rline1(psi_path).rpartition('=')[2]) return float(rline1(psi_path).rpartition('=')[2])
@ -510,11 +493,6 @@ def find_victim_and_send_signal(signal):
if victim_badness >= min_badness: if victim_badness >= min_badness:
# Try to send signal to found victim # Try to send signal to found victim
# Get VmRSS and VmSwap and cmdline of victim process # Get VmRSS and VmSwap and cmdline of victim process
@ -566,12 +544,14 @@ def find_victim_and_send_signal(signal):
except FileNotFoundError: except FileNotFoundError:
print(mem_info) print(mem_info)
print('The victim died in the search process: FileNotFoundError') print('The victim died in the search process: FileNotFoundError')
update_stat_dict_and_print('The victim died in the search process: FileNotFoundError') update_stat_dict_and_print(
'The victim died in the search process: FileNotFoundError')
return None return None
except ProcessLookupError: except ProcessLookupError:
print(mem_info) print(mem_info)
print('The victim died in the search process: ProcessLookupError') print('The victim died in the search process: ProcessLookupError')
update_stat_dict_and_print('The victim died in the search process: ProcessLookupError') update_stat_dict_and_print(
'The victim died in the search process: ProcessLookupError')
return None return None
except UnicodeDecodeError: except UnicodeDecodeError:
@ -585,7 +565,8 @@ def find_victim_and_send_signal(signal):
uid = f_list[i].split('\t')[2] uid = f_list[i].split('\t')[2]
if i is vm_size_index: if i is vm_size_index:
vm_size = kib_to_mib(int(f_list[i].split('\t')[1][:-3])) vm_size = kib_to_mib(
int(f_list[i].split('\t')[1][:-3]))
if i is vm_rss_index: if i is vm_rss_index:
vm_rss = kib_to_mib(int(f_list[i].split('\t')[1][:-3])) vm_rss = kib_to_mib(int(f_list[i].split('\t')[1][:-3]))
@ -605,8 +586,8 @@ def find_victim_and_send_signal(signal):
int(f_list[i].split('\t')[1][:-3])) int(f_list[i].split('\t')[1][:-3]))
if i is vm_swap_index: if i is vm_swap_index:
vm_swap = kib_to_mib(int(f_list[i].split('\t')[1][:-3])) vm_swap = kib_to_mib(
int(f_list[i].split('\t')[1][:-3]))
with open('/proc/' + pid + '/cmdline') as file: with open('/proc/' + pid + '/cmdline') as file:
cmdline = file.readlines()[0].replace('\x00', ' ') cmdline = file.readlines()[0].replace('\x00', ' ')
@ -617,15 +598,16 @@ def find_victim_and_send_signal(signal):
except IndexError: except IndexError:
print(mem_info) print(mem_info)
print('The victim died in the search process: IndexError') print('The victim died in the search process: IndexError')
update_stat_dict_and_print('The victim died in the search process: IndexError') update_stat_dict_and_print(
'The victim died in the search process: IndexError')
return None return None
except ValueError: except ValueError:
print(mem_info) print(mem_info)
print('The victim died in the search process: ValueError') print('The victim died in the search process: ValueError')
update_stat_dict_and_print('The victim died in the search process: ValueError') update_stat_dict_and_print(
'The victim died in the search process: ValueError')
return None return None
len_vm = len(str(vm_size)) len_vm = len(str(vm_size))
if detailed_rss: if detailed_rss:
@ -679,16 +661,6 @@ def find_victim_and_send_signal(signal):
str(vm_swap).rjust(len_vm), str(vm_swap).rjust(len_vm),
cmdline) cmdline)
if execute_the_command and signal is SIGTERM and name in etc_dict: if execute_the_command and signal is SIGTERM and name in etc_dict:
command = etc_dict[name] command = etc_dict[name]
exit_status = os.system(etc_dict[name].replace( exit_status = os.system(etc_dict[name].replace(
@ -719,21 +691,15 @@ def find_victim_and_send_signal(signal):
name, name,
command.replace('$PID', pid).replace('$NAME', pid_to_name(pid))) command.replace('$PID', pid).replace('$NAME', pid_to_name(pid)))
else: else:
try: try:
t0 = time()
m = check_mem_and_swap() m = check_mem_and_swap()
ma = round(int(m[0]) / 1024.0) ma = round(int(m[0]) / 1024.0)
sf = round(int(m[2]) / 1024.0) sf = round(int(m[2]) / 1024.0)
print('\nMemory status before sending a signal:\nMemAv: {} MiB, SwFree: {} MiB'.format(ma, sf)) print('\nMemory status before sending a signal:\nMemA'
print(time() - t0) 'v: {} MiB, SwFree: {} MiB'.format(ma, sf))
os.kill(int(pid), signal) os.kill(int(pid), signal)
response_time = time() - time0 response_time = time() - time0
@ -748,10 +714,6 @@ def find_victim_and_send_signal(signal):
key = 'Send \033[35m{}\033[0m to \033[35m{}\033[0m'.format( key = 'Send \033[35m{}\033[0m to \033[35m{}\033[0m'.format(
sig_dict[signal], name) sig_dict[signal], name)
# zenity()
if gui_notifications: if gui_notifications:
send_notify(signal, name, pid) send_notify(signal, name, pid)
@ -766,15 +728,11 @@ def find_victim_and_send_signal(signal):
round(response_time * 1000)) round(response_time * 1000))
key = 'The victim died in the search process: ProcessLookupError' key = 'The victim died in the search process: ProcessLookupError'
print(mem_info) print(mem_info)
print(preventing_oom_message) print(preventing_oom_message)
update_stat_dict_and_print(key) update_stat_dict_and_print(key)
else: else:
response_time = time() - time0 response_time = time() - time0
@ -791,11 +749,9 @@ def find_victim_and_send_signal(signal):
key = 'victim badness < min_badness' key = 'victim badness < min_badness'
update_stat_dict_and_print(key) update_stat_dict_and_print(key)
sleep_after_send_signal(signal) sleep_after_send_signal(signal)
def sleep_after_check_mem(): def sleep_after_check_mem():
"""Specify sleep times depends on rates and avialable memory.""" """Specify sleep times depends on rates and avialable memory."""
@ -955,6 +911,8 @@ cd = os.getcwd()
config = '/etc/nohang/nohang.conf' config = '/etc/nohang/nohang.conf'
# config = 'nohang.conf'
print('Config:', config) print('Config:', config)
@ -1121,7 +1079,6 @@ else:
exit() exit()
# НУЖНА ВАЛИДАЦИЯ НА МЕСТЕ!
if 'swap_min_sigterm' in config_dict: if 'swap_min_sigterm' in config_dict:
swap_min_sigterm = config_dict['swap_min_sigterm'] swap_min_sigterm = config_dict['swap_min_sigterm']
else: else:
@ -1129,7 +1086,6 @@ else:
exit() exit()
# НУЖНА ВАЛИДАЦИЯ НА МЕСТЕ!
if 'swap_min_sigkill' in config_dict: if 'swap_min_sigkill' in config_dict:
swap_min_sigkill = config_dict['swap_min_sigkill'] swap_min_sigkill = config_dict['swap_min_sigkill']
else: else:
@ -1249,7 +1205,6 @@ else:
exit() exit()
# НА МЕСТЕ!!!
if 'swap_min_warnings' in config_dict: if 'swap_min_warnings' in config_dict:
swap_min_warnings = config_dict['swap_min_warnings'] swap_min_warnings = config_dict['swap_min_warnings']
else: else:
@ -1260,50 +1215,72 @@ else:
########################################################################## ##########################################################################
# Get Kibibytes levels # Get KiB levels if it's possible.
# получ кб. если не кб - то процент. Если процент - находим кб ниже на
# основе полученного своптотал и процентов.
# Returns Kibibytes value if absolute value was set in config, def get_swap_threshold_tuple(string):
# or tuple with percentage # re (Num %, True) or (Num KiB, False)
def sig_level_to_kb_swap(string): """Returns KiB value if abs val was set in config, or tuple with %"""
"""Returns Kibibytes value if abs val was set in config, or tuple with %""" # return tuple with abs and bool: (abs %, True) or (abs MiB, False)
if string.endswith('%'): if string.endswith('%'):
return float(string[:-1].strip()), True valid = string_to_float_convert_test(string[:-1])
if valid is None:
print('somewhere swap unit is not float_%')
exit()
value = float(string[:-1].strip())
if value < 0 or value > 100:
print('invalid value, must be from the range[0; 100] %')
exit()
return value, True
elif string.endswith('M'): elif string.endswith('M'):
return float(string[:-1].strip()) * 1024 valid = string_to_float_convert_test(string[:-1])
if valid is None:
print('somewhere swap unit is not float_M')
exit()
value = float(string[:-1].strip()) * 1024
if value < 0:
print('invalid unit in config (negative value)')
exit()
return value, False
else: else:
print('Invalid config file. There are invalid units somewhere\nExit') print('Invalid config file. There are invalid units somewhere\nExit')
exit() exit()
# So, get them swap_min_sigterm_tuple = get_swap_threshold_tuple(swap_min_sigterm)
swap_min_sigterm_swap = sig_level_to_kb_swap(swap_min_sigterm) swap_min_sigkill_tuple = get_swap_threshold_tuple(swap_min_sigkill)
swap_min_sigkill_swap = sig_level_to_kb_swap(swap_min_sigkill) swap_min_warnings_tuple = get_swap_threshold_tuple(swap_min_warnings)
swap_min_warnings_swap = sig_level_to_kb_swap(swap_min_warnings)
if isinstance(swap_min_sigterm_swap, tuple): swap_term_is_percent = swap_min_sigterm_tuple[1]
swap_term_is_percent = True if swap_term_is_percent:
swap_min_sigterm_percent = swap_min_sigterm_swap[0] swap_min_sigterm_percent = swap_min_sigterm_tuple[0]
else: else:
swap_term_is_percent = False swap_min_sigterm_kb = swap_min_sigterm_tuple[0]
swap_min_sigterm_kb = swap_min_sigterm_swap
if isinstance(swap_min_sigkill_swap, tuple):
swap_kill_is_percent = True swap_kill_is_percent = swap_min_sigkill_tuple[1]
swap_min_sigkill_percent = swap_min_sigkill_swap[0] if swap_kill_is_percent:
swap_min_sigkill_percent = swap_min_sigkill_tuple[0]
else: else:
swap_kill_is_percent = False swap_min_sigkill_kb = swap_min_sigkill_tuple[0]
swap_min_sigkill_kb = swap_min_sigkill_swap
if isinstance(swap_min_warnings_swap, tuple): swap_warn_is_percent = swap_min_warnings_tuple[1]
swap_warn_is_percent = True if swap_warn_is_percent:
swap_min_warnings_percent = swap_min_warnings_swap[0] swap_min_warnings_percent = swap_min_warnings_tuple[0]
else: else:
swap_warn_is_percent = False swap_min_warnings_kb = swap_min_warnings_tuple[0]
swap_min_warnings_kb = swap_min_warnings_swap
########################################################################## ##########################################################################
@ -1413,16 +1390,6 @@ if psi_support and not ignore_psi:
avg_value = '' avg_value = ''
while True: while True:
if psi_support and not ignore_psi: if psi_support and not ignore_psi:
@ -1447,6 +1414,8 @@ while True:
mem_available, swap_total, swap_free = check_mem_and_swap() mem_available, swap_total, swap_free = check_mem_and_swap()
# если метры - получаем киб выше и сразу. см.
# if swap_min_sigkill is set in percent # if swap_min_sigkill is set in percent
if swap_kill_is_percent: if swap_kill_is_percent:
swap_min_sigkill_kb = swap_total * swap_min_sigkill_percent / 100.0 swap_min_sigkill_kb = swap_total * swap_min_sigkill_percent / 100.0
@ -1457,6 +1426,9 @@ while True:
if swap_warn_is_percent: if swap_warn_is_percent:
swap_min_warnings_kb = swap_total * swap_min_warnings_percent / 100.0 swap_min_warnings_kb = swap_total * swap_min_warnings_percent / 100.0
# в общем случае для работы нужны килобайты. Если в процентах задано -
# находим КБ тут, после получения своптотал.
mem_used_zram = check_zram() mem_used_zram = check_zram()
if print_mem_check_results: if print_mem_check_results:
@ -1503,6 +1475,8 @@ while True:
# печатать так: SwapTotal = 0, ignore swapspace # печатать так: SwapTotal = 0, ignore swapspace
swap_sigterm_pc = '-' swap_sigterm_pc = '-'
# это для печати меминфо. Все переработать нахрен.
# далее пошло ветвление # далее пошло ветвление
# MEM SWAP KILL # MEM SWAP KILL
@ -1563,7 +1537,7 @@ while True:
percent(mem_available / mem_total), percent(mem_available / mem_total),
kib_to_mib(mem_min_sigterm_kb), kib_to_mib(mem_min_sigterm_kb),
# percent(mem_min_sigterm_kb / mem_total), # percent(mem_min_sigterm_kb / mem_total),
# ОКРУГЛЯТЬ НА МЕСТЕ ВЫШЕ # ОКРУГЛЯТЬ НА МЕСТЕ ВЫШЕ (или не выше, хз)
round(mem_min_sigterm_percent, 1), round(mem_min_sigterm_percent, 1),
kib_to_mib(swap_free), kib_to_mib(swap_free),
percent(swap_free / (swap_total + 0.1)), percent(swap_free / (swap_total + 0.1)),