add --version and --test flags

This commit is contained in:
Alexey Avramov 2019-03-06 02:32:03 +09:00
parent 87677465ce
commit e568f416a3
3 changed files with 163 additions and 49 deletions

View File

@ -1,10 +1,10 @@
# VERSION ?= $(shell git describe --tags --long --dirty > /etc/nohang/version 2> /dev/null)
PREFIX = / PREFIX = /
all: all:
@ echo "Nothing to compile. Use: make install, make uninstall, make systemd" @ echo "Nothing to compile. Use: make install, make uninstall, make systemd"
install: install:
install -d $(DESTDIR)/$(PREFIX)/usr/sbin install -d $(DESTDIR)/$(PREFIX)/usr/sbin
install -m0755 ./nohang $(DESTDIR)/$(PREFIX)/usr/sbin/nohang install -m0755 ./nohang $(DESTDIR)/$(PREFIX)/usr/sbin/nohang
install -m0755 ./nohang_notify_helper $(DESTDIR)/$(PREFIX)/usr/sbin/nohang_notify_helper install -m0755 ./nohang_notify_helper $(DESTDIR)/$(PREFIX)/usr/sbin/nohang_notify_helper
@ -14,8 +14,8 @@ install:
install -m0755 ./oom-trigger $(DESTDIR)/$(PREFIX)/usr/bin/oom-trigger install -m0755 ./oom-trigger $(DESTDIR)/$(PREFIX)/usr/bin/oom-trigger
install -d $(DESTDIR)/$(PREFIX)/etc/nohang install -d $(DESTDIR)/$(PREFIX)/etc/nohang
install -m0644 ./nohang.conf $(DESTDIR)/$(PREFIX)/etc/nohang install -m0644 ./nohang.conf $(DESTDIR)/$(PREFIX)/etc/nohang/$(VERSION)
install -m0644 ./nohang.conf $(DESTDIR)/$(PREFIX)/etc/nohang/nohang.conf.backup install -m0644 ./nohang.conf $(DESTDIR)/$(PREFIX)/etc/nohang/nohang.conf.default
install -d $(DESTDIR)/$(PREFIX)/usr/share/man/man1 install -d $(DESTDIR)/$(PREFIX)/usr/share/man/man1
gzip -k -c nohang.1 > $(DESTDIR)/$(PREFIX)/usr/share/man/man1/nohang.1.gz gzip -k -c nohang.1 > $(DESTDIR)/$(PREFIX)/usr/share/man/man1/nohang.1.gz

175
nohang
View File

@ -7,6 +7,7 @@ from time import sleep, time
from operator import itemgetter from operator import itemgetter
from sys import stdout, stderr, argv, exit from sys import stdout, stderr, argv, exit
from signal import SIGKILL, SIGTERM from signal import SIGKILL, SIGTERM
import sys
start_time = time() start_time = time()
@ -50,11 +51,10 @@ HR = ''
victim_dict = dict() victim_dict = dict()
# extra_process_table_info = None
extra_process_table_info = None # will store corrective actions stat
stat_dict = dict()
########################################################################## ##########################################################################
@ -62,6 +62,87 @@ extra_process_table_info = None
# define functions # define functions
def print_version():
try:
v = rline1('/etc/nohang/version')
except FileNotFoundError:
v = None
if v is None:
print('nohang unknown version')
else:
print(v)
exit()
def test():
print(sys.version)
print(sys.argv)
hr = '=================================='
print(hr)
print("uptime()")
print(uptime())
print(hr)
print("pid_to_starttime('self')")
print(pid_to_starttime('self'))
print(hr)
print("get_victim_id('self')")
print(get_victim_id('self'))
print(hr)
print("errprint('test')")
print(errprint('test'))
print(hr)
print("mlockall()")
print(mlockall())
print(hr)
print("pid_to_state('2')")
print(pid_to_state('2'))
'''
print(hr)
print("update_stat_dict_and_print('key')")
print(update_stat_dict_and_print('key'))
print(hr)
print("psi_mem_some_avg_total()")
print(psi_mem_some_avg_total())
print(hr)
print("psi_mem_some_avg10()")
print(psi_mem_some_avg10())
print(hr)
print("check_mem()")
print(check_mem())
print(hr)
print("os.uname()")
print(os.uname())
print(hr)
print("check_mem()")
print(check_mem())
'''
print(hr)
exit()
def uptime(): def uptime():
return float(rline1('/proc/uptime').split(' ')[0]) return float(rline1('/proc/uptime').split(' ')[0])
@ -146,11 +227,13 @@ def psi_mem_some_avg_total():
def psi_mem_some_avg10(): def psi_mem_some_avg10():
return float(rline1(psi_path).split(' ')[1].split('=')[1]) if psi_support:
return float(rline1(psi_path).split(' ')[1].split('=')[1])
def check_mem(): def check_mem():
"""find mem_available""" """find mem_available"""
# исправить название фции
return int(rline1('/proc/meminfo').split(':')[1][:-4]) return int(rline1('/proc/meminfo').split(':')[1][:-4])
@ -402,7 +485,6 @@ def pid_to_cmdline(pid):
return f.read().replace('\x00', ' ').rstrip() return f.read().replace('\x00', ' ').rstrip()
def pid_to_realpath(pid): def pid_to_realpath(pid):
try: try:
return os.path.realpath('/proc/' + pid + '/exe') return os.path.realpath('/proc/' + pid + '/exe')
@ -410,10 +492,6 @@ def pid_to_realpath(pid):
return '' return ''
def pid_to_uid(pid): def pid_to_uid(pid):
'''return euid''' '''return euid'''
try: try:
@ -508,6 +586,8 @@ def send_notify_warn():
round(swap_free / (swap_total + 0.1) * 100) round(swap_free / (swap_total + 0.1) * 100)
) )
b = 'head ' + str(b.encode())
t0 = time() t0 = time()
os.system(b) os.system(b)
t1 = time() t1 = time()
@ -682,7 +762,7 @@ def find_victim():
pid_to_uid(pid).rjust(10), pid_to_uid(pid).rjust(10),
pid_to_cmdline(pid) pid_to_cmdline(pid)
# pid_to_realpath(pid) # pid_to_realpath(pid)
) )
) )
pid_badness_list.append((pid, badness)) pid_badness_list.append((pid, badness))
@ -718,7 +798,6 @@ def find_victim():
def find_victim_info(pid, victim_badness, name): def find_victim_info(pid, victim_badness, name):
status0 = time() status0 = time()
try: try:
@ -964,7 +1043,9 @@ def implement_corrective_action(signal):
etc_info = '\nImplement a corrective action:\n Run the command: {}' \ etc_info = '\nImplement a corrective action:\n Run the command: {}' \
'\n Exit status: {}; total response time: {} ms'.format( '\n Exit status: {}; total response time: {} ms'.format(
command.replace('$PID', pid).replace('$NAME', pid_to_name(pid)), command.replace(
'$PID', pid).replace(
'$NAME', pid_to_name(pid)),
exit_status, exit_status,
round(response_time * 1000)) round(response_time * 1000))
@ -1042,7 +1123,6 @@ def implement_corrective_action(signal):
key = 'victim badness < min_badness' key = 'victim badness < min_badness'
update_stat_dict_and_print(key) update_stat_dict_and_print(key)
print('###############################################################################') print('###############################################################################')
sleep_after_send_signal(signal) sleep_after_send_signal(signal)
@ -1167,6 +1247,11 @@ def calculate_percent(arg_key):
########################################################################## ##########################################################################
if len(argv) == 1: if len(argv) == 1:
if os.path.exists('./nohang.conf'): if os.path.exists('./nohang.conf'):
config = cd = os.getcwd() + '/nohang.conf' config = cd = os.getcwd() + '/nohang.conf'
@ -1175,8 +1260,12 @@ if len(argv) == 1:
elif len(argv) == 2: elif len(argv) == 2:
if argv[1] == '--help' or argv[1] == '-h': if argv[1] == '--help' or argv[1] == '-h':
errprint(help_mess) print(help_mess)
exit(1) exit()
elif argv[1] == '--version' or argv[1] == '-v':
print_version()
elif argv[1] == '--test' or argv[1] == '-t':
test()
else: else:
errprint('Invalid CLI input') errprint('Invalid CLI input')
exit(1) exit(1)
@ -1193,6 +1282,14 @@ else:
exit(1) exit(1)
########################################################################## ##########################################################################
@ -1267,8 +1364,7 @@ uid_re_list = []
# тут тоже список нужен, а не словарь # тут тоже список нужен, а не словарь
etc_dict = dict() etc_dict = dict()
# will store corrective actions stat
stat_dict = dict()
try: try:
with open(config) as f: with open(config) as f:
@ -1340,14 +1436,7 @@ except FileNotFoundError:
# validation of all parameters # validation of all parameters
print_victim_info = conf_parse_bool('print_victim_info') print_victim_info = conf_parse_bool('print_victim_info')
print_config = conf_parse_bool('print_config') print_config = conf_parse_bool('print_config')
print_mem_check_results = conf_parse_bool('print_mem_check_results') print_mem_check_results = conf_parse_bool('print_mem_check_results')
print_sleep_periods = conf_parse_bool('print_sleep_periods') print_sleep_periods = conf_parse_bool('print_sleep_periods')
@ -1355,16 +1444,12 @@ gui_low_memory_warnings = conf_parse_bool('gui_low_memory_warnings')
gui_notifications = conf_parse_bool('gui_notifications') gui_notifications = conf_parse_bool('gui_notifications')
decrease_oom_score_adj = conf_parse_bool('decrease_oom_score_adj') decrease_oom_score_adj = conf_parse_bool('decrease_oom_score_adj')
execute_the_command = conf_parse_bool('execute_the_command') execute_the_command = conf_parse_bool('execute_the_command')
ignore_psi = conf_parse_bool('ignore_psi') ignore_psi = conf_parse_bool('ignore_psi')
regex_matching = conf_parse_bool('regex_matching') regex_matching = conf_parse_bool('regex_matching')
re_match_cmdline = conf_parse_bool('re_match_cmdline') re_match_cmdline = conf_parse_bool('re_match_cmdline')
re_match_uid = conf_parse_bool('re_match_uid') re_match_uid = conf_parse_bool('re_match_uid')
if regex_matching or re_match_cmdline or re_match_uid: if regex_matching or re_match_cmdline or re_match_uid:
from re import search from re import search
import sre_constants import sre_constants
@ -1648,6 +1733,30 @@ if max_sleep_time < min_sleep_time:
########################################################################## ##########################################################################
# Get KiB levels if it's possible. # Get KiB levels if it's possible.
# получ кб. если не кб - то процент. Если процент - находим кб ниже на # получ кб. если не кб - то процент. Если процент - находим кб ниже на
@ -1851,6 +1960,9 @@ if print_mem_check_results:
report0 = 0 report0 = 0
while True: while True:
if psi_support and not ignore_psi: if psi_support and not ignore_psi:
@ -1944,7 +2056,8 @@ while True:
just_percent_mem(mem_available / mem_total), just_percent_mem(mem_available / mem_total),
human(swap_free, swap_len), human(swap_free, swap_len),
just_percent_swap(swap_free / (swap_total + 0.1)), just_percent_swap(swap_free / (swap_total + 0.1)),
speed_info) speed_info
)
) )
else: else:

View File

@ -4,14 +4,14 @@
# ./nohang_notify_helper "title" "body" # ./nohang_notify_helper "title" "body"
from sys import argv, stdout from sys import argv, stdout
from os import listdir from os import listdir, path
from subprocess import Popen, TimeoutExpired from subprocess import Popen, TimeoutExpired
if len(argv) < 2 or argv[1] == "-h" or argv[1] == "--help": if len(argv) < 2 or argv[1] == "-h" or argv[1] == "--help":
print('Usage: ./nohang_notify_helper "title" "body"') print('Usage: ./nohang_notify_helper "title" "body"')
exit(1) exit(1)
wait_time = 10 wait_time = 15
display_env = 'DISPLAY=' display_env = 'DISPLAY='
dbus_env = 'DBUS_SESSION_BUS_ADDRESS=' dbus_env = 'DBUS_SESSION_BUS_ADDRESS='
@ -57,21 +57,19 @@ def re_pid_environ(pid):
if i.startswith('HOME=/var'): if i.startswith('HOME=/var'):
return None return None
try: try:
# dirty hack; todo: fix alg
env = user.partition('USER=')[2], display, dbus env = user.partition('USER=')[2], display, dbus
except UnboundLocalError: except UnboundLocalError:
print('notify helper: UnboundLocalError') # print('notify helper: UnboundLocalError')
return None return None
return env return env
except FileNotFoundError: except FileNotFoundError:
print('notify helper: FileNotFoundError') # print('notify helper: FileNotFoundError')
return None return None
except ProcessLookupError: except ProcessLookupError:
print('notify helper: ProcessLookupError') # print('notify helper: ProcessLookupError')
return None return None
@ -80,10 +78,11 @@ def root_notify_env():
unsorted_envs_list = [] unsorted_envs_list = []
# iterates over processes, find processes with suitable env # iterates over processes, find processes with suitable env
for pid in listdir('/proc'): for pid in listdir('/proc'):
if pid[0].isdecimal() is False:
continue if path.exists('/proc/' + pid + '/exe') is True:
one_env = re_pid_environ(pid) one_env = re_pid_environ(pid)
unsorted_envs_list.append(one_env) unsorted_envs_list.append(one_env)
env = set(unsorted_envs_list) env = set(unsorted_envs_list)
env.discard(None) env.discard(None)
@ -134,6 +133,8 @@ if list_len > 0:
proc.kill() proc.kill()
print('TimeoutExpired: notify user:' + username) print('TimeoutExpired: notify user:' + username)
else: else:
print('Not send GUI notification: [', argv[1], argv[2], ']. Nobody logged-in with GUI. Nothing to do.') print(
'Not send GUI notification: [',
stdout.flush() argv[1],
argv[2],
']. Nobody logged-in with GUI. Nothing to do.')