Add support for manually triggered OOM (suggested by Mikko Rantalainen)
Add support for systems w/o swap (suggested by Mikko Rantalainen)
+
Add support for newer kernels (suggested by Mikko Rantalainen)
...
diff --git a/OOMAnalyser.py b/OOMAnalyser.py
index c48c0a7..868492d 100644
--- a/OOMAnalyser.py
+++ b/OOMAnalyser.py
@@ -153,7 +153,17 @@ class BaseKernelConfig:
name = 'Base configuration for all kernels'
"""Name/description of this kernel configuration"""
- EXTRACT_PATTERN = {
+ EXTRACT_PATTERN = None
+ """
+ Instance specific dictionary of RE pattern to analyse a OOM block for a specific kernel version
+
+ This dict will be filled from EXTRACT_PATTERN_BASE and EXTRACT_PATTERN_OVERLAY during class constructor is executed.
+
+ :type: None|Dict
+ :see: EXTRACT_PATTERN_BASE and EXTRACT_PATTERN_OVERLAY
+ """
+
+ EXTRACT_PATTERN_BASE = {
'invoked oom-killer': (
r'^(?P[\S ]+) invoked oom-killer: '
r'gfp_mask=(?P0x[a-z0-9]+)(\((?P[A-Z_|]+)\))?, '
@@ -255,7 +265,18 @@ class BaseKernelConfig:
The first item is the RE pattern and the second is whether it is mandatory to find this pattern.
+ This dictionary will be copied to EXTRACT_PATTERN during class constructor is executed.
+
:type: dict(tuple(str, bool))
+ :see: EXTRACT_PATTERN
+ """
+
+ EXTRACT_PATTERN_OVERLAY = {}
+ """
+ To extend / overwrite parts of EXTRACT_PATTERN in kernel configuration.
+
+ :type: dict(tuple(str, bool))
+ :see: EXTRACT_PATTERN
"""
GFP_FLAGS = {
@@ -325,22 +346,137 @@ class BaseKernelConfig:
rec_version4kconfig = re.compile('.+')
"""RE to match kernel version to kernel configuration"""
- rec_oom_begin = re.compile('invoked oom-killer:', re.MULTILINE)
+ rec_oom_begin = re.compile(r'invoked oom-killer:', re.MULTILINE)
"""RE to match the first line of an OOM block"""
- rec_oom_end = re.compile('^Killed process \d+', re.MULTILINE)
+ rec_oom_end = re.compile(r'^Killed process \d+', re.MULTILINE)
"""RE to match the last line of an OOM block"""
+ def __init__(self):
+ super().__init__()
+
+ if self.EXTRACT_PATTERN is None:
+ # Create a copy to prevent modifications on the class dictionary
+ # TODO replace with self.EXTRACT_PATTERN = self.EXTRACT_PATTERN.copy() after
+ # https://github.com/QQuick/Transcrypt/issues/716 "dict does not have a copy method" is fixed
+ self.EXTRACT_PATTERN = {}
+ self.EXTRACT_PATTERN.update(self.EXTRACT_PATTERN_BASE)
+
+ if self.EXTRACT_PATTERN_OVERLAY:
+ self.EXTRACT_PATTERN.update(self.EXTRACT_PATTERN_OVERLAY)
+
+
+class KernelConfig_4_6(BaseKernelConfig):
+ # Support changes:
+ # * "mm, oom_reaper: report success/failure" (bc448e897b6d24aae32701763b8a1fe15d29fa26)
+
+ name = 'Configuration for Linux kernel 4.6 or later'
+ rec_version4kconfig = re.compile(r'^4\.([6-9]\.|[12][0-9]\.).+')
+
+ # The "oom_reaper" line is optionally
+ rec_oom_end = re.compile(r'^((Out of memory.*|Memory cgroup out of memory): Killed process \d+|oom_reaper:)',
+ re.MULTILINE)
+
+ def __init__(self):
+ super().__init__()
+
+
+class KernelConfig_4_9(KernelConfig_4_6):
+ # Support changes:
+ # * "mm: oom: deduplicate victim selection code for memcg and global oom" (7c5f64f84483bd13886348edda8b3e7b799a7fdb)
+
+ name = 'Configuration for Linux kernel 4.9 or later'
+ rec_version4kconfig = re.compile(r'^4\.([9]\.|[12][0-9]\.).+')
+
+ EXTRACT_PATTERN_OVERLAY_49 = {
+ 'Details of process killed by OOM': (
+ r'^(Out of memory.*|Memory cgroup out of memory): Killed process \d+ \(.*\)'
+ r'(, UID \d+,)?'
+ r' total-vm:(?P\d+)kB, anon-rss:(?P\d+)kB, '
+ r'file-rss:(?P\d+)kB, shmem-rss:(?P\d+)kB.*',
+ True,
+ ),
+ }
+
+ def __init__(self):
+ super().__init__()
+ self.EXTRACT_PATTERN.update(self.EXTRACT_PATTERN_OVERLAY_49)
+
+
+class KernelConfig_5_0(KernelConfig_4_9):
+ # Support changes:
+ # * "mm, oom: reorganize the oom report in dump_header" (ef8444ea01d7442652f8e1b8a8b94278cb57eafd)
+
+ name = 'Configuration for Linux kernel 5.0 or later'
+ rec_version4kconfig = re.compile(r'^[5-9]\..+')
+
+ EXTRACT_PATTERN_OVERLAY_50 = {
+ # third last line - not integrated yet
+ # oom-kill:constraint=CONSTRAINT_NONE,nodemask=(null),cpuset=/,mems_allowed=0,global_oom,task_memcg=/,task=sed,pid=29481,uid=12345
+
+ 'Process killed by OOM': (
+ r'^Out of memory: Killed process (?P\d+) \((?P[\S ]+)\) '
+ r'total-vm:(?P\d+)kB, anon-rss:(?P\d+)kB, '
+ r'file-rss:(?P\d+)kB, shmem-rss:(?P\d+)kB, '
+ r'UID:\d+ pgtables:(?P\d+)kB oom_score_adj:(?P\d+)',
+ True,
+ ),
+ }
+
+ def __init__(self):
+ super().__init__()
+ self.EXTRACT_PATTERN.update(self.EXTRACT_PATTERN_OVERLAY_50)
+
+
+class KernelConfig_5_8(KernelConfig_5_0):
+ # Support changes:
+ # * "mm/writeback: discard NR_UNSTABLE_NFS, use NR_WRITEBACK instead" (8d92890bd6b8502d6aee4b37430ae6444ade7a8c)
+
+ name = 'Configuration for Linux kernel 5.8 or later'
+
+ rec_version4kconfig = re.compile(r'^(5\.[8-9]\.|5\.[1-9][0-9]\.|[6-9]\.).+')
+
+ EXTRACT_PATTERN_OVERLAY_58 = {
+ 'Mem-Info (part 1)': (
+ r'^Mem-Info:.*'
+ r'(?:\n)'
+
+ # first line (starting w/o a space)
+ r'^active_anon:(?P\d+) inactive_anon:(?P\d+) '
+ r'isolated_anon:(?P\d+)'
+ r'(?:\n)'
+
+ # remaining lines (w/ leading space)
+ r'^ active_file:(?P\d+) inactive_file:(?P\d+) '
+ r'isolated_file:(?P\d+)'
+ r'(?:\n)'
+
+ r'^ unevictable:(?P\d+) dirty:(?P\d+) writeback:(?P\d+)',
+ True,
+ ),
+ }
+
+ def __init__(self):
+ super().__init__()
+ self.EXTRACT_PATTERN.update(self.EXTRACT_PATTERN_OVERLAY_58)
+
class KernelConfigRhel7(BaseKernelConfig):
"""RHEL7 / CentOS7 specific configuration"""
- name = 'RHEL7 / CentOS7 specific kernel configuration'
+ name = 'Configuration for RHEL7 / CentOS7 specific Linux kernel (3.10)'
- rec_version4kconfig = re.compile('^3\..+')
+ rec_version4kconfig = re.compile(r'^3\..+')
+
+ def __init__(self):
+ super().__init__()
AllKernelConfigs = [
+ KernelConfig_5_8(),
+ KernelConfig_5_0(),
+ KernelConfig_4_9(),
+ KernelConfig_4_6(),
KernelConfigRhel7(),
BaseKernelConfig(),
]
@@ -426,6 +562,7 @@ class OOMEntity:
"""Remove all lines before and after OOM message block"""
cleaned_lines = []
in_oom_lines = False
+ killed_process = False
for line in oom_lines:
# first line of the oom message block
@@ -435,9 +572,21 @@ class OOMEntity:
if in_oom_lines:
cleaned_lines.append(line)
- # next line will not be part of the oom anymore
+ # OOM blocks ends with the second last only or both lines
+ # Out of memory: Killed process ...
+ # oom_reaper: reaped process ...
if 'Killed process' in line:
- break
+ killed_process = True
+ continue
+
+ # next line after "Killed process \d+ ..."
+ if killed_process:
+ if 'oom_reaper' in line:
+ break
+ else:
+ # remove this line
+ del cleaned_lines[-1]
+ break
return cleaned_lines
@@ -666,8 +815,8 @@ class OOMAnalyser:
if not self.oom_result.kconfig.rec_oom_end.search(self.oom_entity.text):
self.state = OOMEntityState.started
- self.oom_result.error_msg = 'The inserted OOM is incomplete! The initial pattern was found ' \
- 'but not the final. The result may be incomplete!'
+ self.oom_result.error_msg = 'The inserted OOM is incomplete! The initial pattern was found but not the '\
+ 'final.'
return False
self.state = OOMEntityState.complete
@@ -1026,7 +1175,7 @@ class OOMDisplay:
@rtype: OOMResult
"""
- example = u'''\
+ example_rhel7 = u'''\
sed invoked oom-killer: gfp_mask=0x201da, order=0, oom_score_adj=0
sed cpuset=/ mems_allowed=0-1
CPU: 4 PID: 29481 Comm: sed Not tainted 3.10.0-514.6.1.el7.x86_64 #1
@@ -1167,6 +1316,78 @@ Total swap = 8388604kB
[29752] 12345 29752 7522 296 19 0 0 rotatelogs
Out of memory: Kill process 6576 (mysqld) score 651 or sacrifice child
Killed process 6576 (mysqld) total-vm:33914892kB, anon-rss:20629004kB, file-rss:0kB, shmem-rss:0kB
+'''
+
+ example_ubuntu2110 = u'''\
+kworker/0:2 invoked oom-killer: gfp_mask=0xcc0(GFP_KERNEL), order=-1, oom_score_adj=0
+CPU: 0 PID: 735 Comm: kworker/0:2 Not tainted 5.13.0-19-generic #19-Ubuntu
+Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS ArchLinux 1.14.0-1 04/01/2014
+Workqueue: events moom_callback
+Call Trace:
+ show_stack+0x52/0x58
+ dump_stack+0x7d/0x9c
+ dump_header+0x4f/0x1f9
+ oom_kill_process.cold+0xb/0x10
+ out_of_memory.part.0+0xce/0x270
+ out_of_memory+0x41/0x80
+ moom_callback+0x7a/0xb0
+ process_one_work+0x220/0x3c0
+ worker_thread+0x53/0x420
+ kthread+0x11f/0x140
+ ? process_one_work+0x3c0/0x3c0
+ ? set_kthread_struct+0x50/0x50
+ ret_from_fork+0x22/0x30
+Mem-Info:
+active_anon:221 inactive_anon:14331 isolated_anon:0
+ active_file:18099 inactive_file:22324 isolated_file:0
+ unevictable:4785 dirty:633 writeback:0
+ slab_reclaimable:6027 slab_unreclaimable:6546
+ mapped:15338 shmem:231 pagetables:412 bounce:0
+ free:427891 free_pcp:153 free_cma:0
+Node 0 active_anon:884kB inactive_anon:57324kB active_file:72396kB inactive_file:89296kB unevictable:19140kB isolated(anon):0kB isolated(file):0kB mapped:61352kB dirty:2532kB writeback:0kB shmem:924kB shmem_thp: 0kB shmem_pmdmapped: 0kB anon_thp: 0kB writeback_tmp:0kB kernel_stack:1856kB pagetables:1648kB all_unreclaimable? no
+Node 0 DMA free:15036kB min:352kB low:440kB high:528kB reserved_highatomic:0KB active_anon:0kB inactive_anon:0kB active_file:0kB inactive_file:0kB unevictable:0kB writepending:0kB present:15992kB managed:15360kB mlocked:0kB bounce:0kB free_pcp:0kB local_pcp:0kB free_cma:0kB
+lowmem_reserve[]: 0 1893 1893 1893 1893
+Node 0 DMA32 free:1696528kB min:44700kB low:55872kB high:67044kB reserved_highatomic:0KB active_anon:884kB inactive_anon:57324kB active_file:72396kB inactive_file:89296kB unevictable:19140kB writepending:2532kB present:2080640kB managed:2010036kB mlocked:19140kB bounce:0kB free_pcp:612kB local_pcp:612kB free_cma:0kB
+lowmem_reserve[]: 0 0 0 0 0
+Node 0 DMA: 1*4kB (U) 1*8kB (U) 1*16kB (U) 1*32kB (U) 0*64kB 1*128kB (U) 0*256kB 1*512kB (U) 0*1024kB 1*2048kB (M) 3*4096kB (M) = 15036kB
+Node 0 DMA32: 0*4kB 4*8kB (UM) 25*16kB (UME) 151*32kB (UM) 56*64kB (UM) 21*128kB (ME) 36*256kB (UME) 47*512kB (UM) 41*1024kB (UM) 32*2048kB (UM) 377*4096kB (UM) = 1696528kB
+Node 0 hugepages_total=0 hugepages_free=0 hugepages_surp=0 hugepages_size=2048kB
+42845 total pagecache pages
+0 pages in swap cache
+Swap cache stats: add 0, delete 0, find 0/0
+Free swap = 0kB
+Total swap = 0kB
+524158 pages RAM
+0 pages HighMem/MovableOnly
+17809 pages reserved
+0 pages hwpoisoned
+Tasks state (memory values in pages):
+[ pid ] uid tgid total_vm rss pgtables_bytes swapents oom_score_adj name
+[ 323] 0 323 9458 2766 77824 0 -250 systemd-journal
+[ 356] 0 356 5886 1346 69632 0 -1000 systemd-udevd
+[ 507] 0 507 70208 4646 98304 0 -1000 multipathd
+[ 542] 101 542 21915 1391 69632 0 0 systemd-timesyn
+[ 587] 102 587 4635 1882 73728 0 0 systemd-network
+[ 589] 103 589 5875 2951 86016 0 0 systemd-resolve
+[ 602] 0 602 1720 322 53248 0 0 cron
+[ 603] 104 603 2159 1168 53248 0 -900 dbus-daemon
+[ 608] 0 608 7543 4677 94208 0 0 networkd-dispat
+[ 609] 107 609 55313 1248 73728 0 0 rsyslogd
+[ 611] 0 611 311571 8248 221184 0 -900 snapd
+[ 613] 0 613 3404 1668 65536 0 0 systemd-logind
+[ 615] 0 615 98223 3142 126976 0 0 udisksd
+[ 620] 0 620 1443 278 45056 0 0 agetty
+[ 623] 0 623 1947 1147 57344 0 0 login
+[ 650] 0 650 3283 1683 65536 0 -1000 sshd
+[ 651] 0 651 27005 5232 106496 0 0 unattended-upgr
+[ 661] 0 661 58546 1812 90112 0 0 polkitd
+[ 856] 1000 856 3789 2157 73728 0 0 systemd
+[ 857] 1000 857 25433 835 86016 0 0 (sd-pam)
+[ 862] 1000 862 2208 1373 53248 0 0 bash
+[ 876] 1000 876 2870 1356 57344 0 0 sudo
+[ 877] 0 877 1899 1052 53248 0 0 bash
+oom-kill:constraint=CONSTRAINT_NONE,nodemask=(null),cpuset=/,mems_allowed=0,global_oom,task_memcg=/system.slice/unattended-upgrades.service,task=unattended-upgr,pid=651,uid=0
+Out of memory: Killed process 651 (unattended-upgr) total-vm:108020kB, anon-rss:8380kB, file-rss:12548kB, shmem-rss:0kB, UID:0 pgtables:104kB oom_score_adj:0
'''
sorted_column = None
@@ -1481,8 +1702,11 @@ Killed process 6576 (mysqld) total-vm:33914892kB, anon-rss:20629004kB, file-rss:
return svg
- def copy_example_to_form(self):
- document.getElementById('textarea_oom').value = self.example
+ def copy_example_rhel7_to_form(self):
+ document.getElementById('textarea_oom').value = self.example_rhel7
+
+ def copy_example_ubuntu_to_form(self):
+ document.getElementById('textarea_oom').value = self.example_ubuntu2110
def reset_form(self):
document.getElementById('textarea_oom').value = ""
@@ -1533,9 +1757,6 @@ Killed process 6576 (mysqld) total-vm:33914892kB, anon-rss:20629004kB, file-rss:
"""
Show all extracted details as well as additionally generated information
"""
- if DEBUG:
- print(self.oom_result.details)
-
hide_element('input')
show_element('analysis')
if self.oom_result.oom_type == OOMEntityType.manual:
diff --git a/test.py b/test.py
index 9d3d128..34f49a3 100755
--- a/test.py
+++ b/test.py
@@ -52,10 +52,15 @@ class TestBase(unittest.TestCase):
def get_lines(self, text, count):
"""
Return the number of lines specified by count from given text
+
@type text: str
@type count: int
"""
- lines = text.splitlines()[:count]
+ lines = text.splitlines()
+ if count < 0:
+ lines.reverse()
+ count = count * -1
+ lines = lines[:count]
res = '\n'.join(lines)
return res
@@ -167,8 +172,8 @@ class TestInBrowser(TestBase):
self.click_analyse()
- def check_results(self):
- """Check the results of the analysis of the default example"""
+ def check_results_rhel7(self):
+ """Check the results of the analysis of the RHEL7 example"""
self.assert_on_warn_error()
h3_summary = self.driver.find_element_by_xpath('//h3[text()="Summary"]')
self.assertTrue(h3_summary.is_displayed(), "Analysis details incl.
Summary
should be displayed")
@@ -193,8 +198,34 @@ class TestInBrowser(TestBase):
explanation = self.driver.find_element_by_id('explanation')
self.assertTrue('OOM killer was automatically triggered' in explanation.text,
'Missing text "OOM killer was automatically triggered"')
+
+ self.check_swap_active()
+
+ def check_results_ubuntu2110(self):
+ """Check the results of the analysis of the Ubuntu example"""
+ dirty_pages = self.driver.find_element_by_class_name('dirty_pages')
+ self.assertEqual(dirty_pages.text, '633 pages', 'Unexpected number of dirty pages')
+
+ ram_pages = self.driver.find_element_by_class_name('ram_pages')
+ self.assertEqual(ram_pages.text, '524158 pages', 'Unexpected number of RAM pages')
+
+ explanation = self.driver.find_element_by_id('explanation')
+ self.assertTrue('OOM killer was manually triggered' in explanation.text,
+ 'Missing text "OOM killer was manually triggered"')
+
+ self.check_swap_inactive()
+
+ def check_swap_inactive(self):
+ explanation = self.driver.find_element_by_id('explanation')
+ self.assertTrue('physical memory and no swap space' in explanation.text,
+ 'Missing text "physical memory and no swap space"')
+ self.assertFalse('swap space are in use' in explanation.text,
+ 'No swap space but text "swap space are in use"')
+
+ def check_swap_active(self):
+ explanation = self.driver.find_element_by_id('explanation')
self.assertTrue('swap space are in use' in explanation.text,
- 'Missing text "swap space are in use"')
+ 'Swap space active but no text "swap space are in use"')
def test_010_load_page(self):
"""Test if the page is loading"""
@@ -205,11 +236,11 @@ class TestInBrowser(TestBase):
elem = self.driver.find_element_by_id("version")
self.assertIsNotNone(elem.text, "Version statement not set - JS not loaded")
- def test_030_insert_and_analyse_example(self):
- """Test loading and analysing example"""
+ def test_030_insert_and_analyse_rhel7_example(self):
+ """Test loading and analysing RHEL7 example"""
textarea = self.driver.find_element_by_id('textarea_oom')
self.assertEqual(textarea.get_attribute('value'), '', 'Empty textarea expected')
- insert_example = self.driver.find_element_by_xpath('//button[text()="Insert example"]')
+ insert_example = self.driver.find_element_by_xpath('//button[contains(text(), "RHEL7" )]')
insert_example.click()
self.assertNotEqual(textarea.get_attribute('value'), '', 'Missing OOM text in textarea')
@@ -217,9 +248,23 @@ class TestInBrowser(TestBase):
self.assertFalse(h3_summary.is_displayed(), "Analysis details incl.
Summary
should be not displayed")
self.click_analyse()
- self.check_results()
+ self.check_results_rhel7()
- def test_031_empty_textarea(self):
+ def test_031_insert_and_analyse_ubuntu_example(self):
+ """Test loading and analysing Ubuntu 21.10 example"""
+ textarea = self.driver.find_element_by_id('textarea_oom')
+ self.assertEqual(textarea.get_attribute('value'), '', 'Empty textarea expected')
+ insert_example = self.driver.find_element_by_xpath('//button[contains(text(), "Ubuntu" )]')
+ insert_example.click()
+ self.assertNotEqual(textarea.get_attribute('value'), '', 'Missing OOM text in textarea')
+
+ h3_summary = self.driver.find_element_by_xpath('//h3[text()="Summary"]')
+ self.assertFalse(h3_summary.is_displayed(), "Analysis details incl.
Summary
should be not displayed")
+
+ self.click_analyse()
+ self.check_results_ubuntu2110()
+
+ def test_032_empty_textarea(self):
"""Test "Analyse" with empty textarea"""
textarea = self.driver.find_element_by_id('textarea_oom')
self.assertEqual(textarea.get_attribute('value'), '', 'Empty textarea expected')
@@ -234,7 +279,7 @@ class TestInBrowser(TestBase):
self.assertEqual(self.get_error_text(), "ERROR: Empty OOM text. Please insert an OOM message block.")
self.click_reset()
- def test_032_begin_but_no_end(self):
+ def test_033_begin_but_no_end(self):
"""Test incomplete OOM text - just the beginning"""
example = """\
sed invoked oom-killer: gfp_mask=0x201da, order=0, oom_score_adj=0
@@ -243,10 +288,10 @@ CPU: 4 PID: 29481 Comm: sed Not tainted 3.10.0-514.6.1.el7.x86_64 #1
"""
self.analyse_oom(example)
self.assertEqual(self.get_error_text(), "ERROR: The inserted OOM is incomplete! The initial pattern was "
- "found but not the final. The result may be incomplete!")
+ "found but not the final.")
self.click_reset()
- def test_033_no_begin_but_end(self):
+ def test_034_no_begin_but_end(self):
"""Test incomplete OOM text - just the end"""
example = """\
Out of memory: Kill process 6576 (java) score 651 or sacrifice child
@@ -258,7 +303,7 @@ Killed process 6576 (java) total-vm:33914892kB, anon-rss:20629004kB, file-rss:0k
def test_040_trigger_proc_space(self):
"""Test trigger process name contains a space"""
- example = OOMAnalyser.OOMDisplay.example
+ example = OOMAnalyser.OOMDisplay.example_rhel7
example = example.replace('sed', 'VM Monitoring Task')
self.analyse_oom(example)
@@ -268,7 +313,7 @@ Killed process 6576 (java) total-vm:33914892kB, anon-rss:20629004kB, file-rss:0k
def test_050_kill_proc_space(self):
"""Test killed process name contains a space"""
- example = OOMAnalyser.OOMDisplay.example
+ example = OOMAnalyser.OOMDisplay.example_rhel7
example = example.replace('mysqld', 'VM Monitoring Task')
self.analyse_oom(example)
@@ -278,8 +323,8 @@ Killed process 6576 (java) total-vm:33914892kB, anon-rss:20629004kB, file-rss:0k
def test_060_removal_of_leading_but_useless_columns(self):
"""Test removal of leading but useless columns"""
- self.analyse_oom(OOMAnalyser.OOMDisplay.example)
- self.check_results()
+ self.analyse_oom(OOMAnalyser.OOMDisplay.example_rhel7)
+ self.check_results_rhel7()
self.click_reset()
for prefix in ["[11686.888109] ",
"Apr 01 14:13:32 mysrv: ",
@@ -289,17 +334,17 @@ Killed process 6576 (java) total-vm:33914892kB, anon-rss:20629004kB, file-rss:0k
"kernel:",
"Apr 01 14:13:32 mysrv kernel:",
]:
- lines = OOMAnalyser.OOMDisplay.example.split('\n')
+ lines = OOMAnalyser.OOMDisplay.example_rhel7.split('\n')
lines = ["{}{}".format(prefix, line) for line in lines]
oom_text = "\n".join(lines)
self.analyse_oom(oom_text)
- self.check_results()
+ self.check_results_rhel7()
self.click_reset()
def test_070_manually_triggered_OOM(self):
"""Test for manually triggered OOM"""
- example = OOMAnalyser.OOMDisplay.example
+ example = OOMAnalyser.OOMDisplay.example_rhel7
example = example.replace('order=0', 'order=-1')
self.analyse_oom(example)
self.assert_on_warn_error()
@@ -310,18 +355,15 @@ Killed process 6576 (java) total-vm:33914892kB, anon-rss:20629004kB, file-rss:0k
def test_080_swap_deactivated(self):
"""Test w/o swap or with deactivated swap"""
- example = OOMAnalyser.OOMDisplay.example
+ example = OOMAnalyser.OOMDisplay.example_rhel7
example = example.replace('Total swap = 8388604kB', 'Total swap = 0kB')
self.analyse_oom(example)
self.assert_on_warn_error()
- explanation = self.driver.find_element_by_id('explanation')
- self.assertFalse('swap space are in use' in explanation.text,
- 'No swap space but text "swap space are in use"')
-
+ self.check_swap_inactive()
self.click_reset()
- example = OOMAnalyser.OOMDisplay.example
+ example = OOMAnalyser.OOMDisplay.example_rhel7
example = re.sub(r'\d+ pages in swap cac.*\n*', '', example, re.MULTILINE)
example = re.sub(r'Swap cache stats.*\n*', '', example)
example = re.sub(r'Free swap.*\n*', '', example)
@@ -329,17 +371,14 @@ Killed process 6576 (java) total-vm:33914892kB, anon-rss:20629004kB, file-rss:0k
self.analyse_oom(example)
self.assert_on_warn_error()
-
- explanation = self.driver.find_element_by_id('explanation')
- self.assertFalse('swap space are in use' in explanation.text,
- 'No swap space but text "swap space are in use"')
+ self.check_swap_inactive()
class TestPython(TestBase):
def test_001_trigger_proc_space(self):
"""Test RE to find name of trigger process"""
- first = self.get_first_line(OOMAnalyser.OOMDisplay.example)
+ first = self.get_first_line(OOMAnalyser.OOMDisplay.example_rhel7)
pattern = OOMAnalyser.OOMAnalyser.oom_result.kconfig.EXTRACT_PATTERN['invoked oom-killer'][0]
rec = re.compile(pattern, re.MULTILINE)
match = rec.search(first)
@@ -351,19 +390,19 @@ class TestPython(TestBase):
def test_002_killed_proc_space(self):
"""Test RE to find name of killed process"""
- last = self.get_last_line(OOMAnalyser.OOMDisplay.example)
+ text = self.get_lines(OOMAnalyser.OOMDisplay.example_rhel7, -2)
pattern = OOMAnalyser.OOMAnalyser.oom_result.kconfig.EXTRACT_PATTERN['Process killed by OOM'][0]
rec = re.compile(pattern, re.MULTILINE)
- match = rec.search(last)
+ match = rec.search(text)
self.assertTrue(match, "Error: re.search('Process killed by OOM') failed for simple process name")
- last = last.replace('sed', 'VM Monitoring Task')
- match = rec.search(last)
+ text = text.replace('sed', 'VM Monitoring Task')
+ match = rec.search(text)
self.assertTrue(match, "Error: re.search('Process killed by OOM') failed for process name with space")
def test_003_OOMEntity_number_of_columns_to_strip(self):
"""Test stripping useless / leading columns"""
- oom_entity = OOMAnalyser.OOMEntity(OOMAnalyser.OOMDisplay.example)
+ oom_entity = OOMAnalyser.OOMEntity(OOMAnalyser.OOMDisplay.example_rhel7)
for pos, line in [
(1, '[11686.888109] CPU: 4 PID: 29481 Comm: sed Not tainted 3.10.0-514.6.1.el7.x86_64 #1'),
(5, 'Apr 01 14:13:32 mysrv kernel: CPU: 4 PID: 29481 Comm: sed Not tainted 3.10.0-514.6.1.el7.x86_64 #1'),
@@ -375,7 +414,7 @@ class TestPython(TestBase):
def test_004_extract_block_from_next_pos(self):
"""Test extracting a single block (all lines till the next line with a colon)"""
- oom = OOMAnalyser.OOMEntity(OOMAnalyser.OOMDisplay.example)
+ oom = OOMAnalyser.OOMEntity(OOMAnalyser.OOMDisplay.example_rhel7)
analyser = OOMAnalyser.OOMAnalyser(oom)
text = analyser._extract_block_from_next_pos('Hardware name:')
expected = '''\
@@ -388,7 +427,7 @@ Hardware name: HP ProLiant DL385 G7, BIOS A18 12/08/2012
def test_005_extract_kernel_version(self):
"""Test extracting kernel version"""
- oom = OOMAnalyser.OOMEntity(OOMAnalyser.OOMDisplay.example)
+ oom = OOMAnalyser.OOMEntity(OOMAnalyser.OOMDisplay.example_rhel7)
analyser = OOMAnalyser.OOMAnalyser(oom)
for text, kversion in [
('CPU: 0 PID: 19163 Comm: kworker/0:0 Tainted: G OE 5.4.0-80-lowlatency #90~18.04.1-Ubuntu', '5.4.0-80-lowlatency'),
@@ -399,6 +438,30 @@ Hardware name: HP ProLiant DL385 G7, BIOS A18 12/08/2012
self.assertTrue(analyser._identify_kernel_version(), analyser.oom_result.error_msg)
self.assertEqual(analyser.oom_result.kversion, kversion)
+ def test_006_choosing_kernel_config(self):
+ """Test choosing the right kernel configuration"""
+ for kcfg, kversion in [
+ (OOMAnalyser.KernelConfig_5_8(), 'CPU: 4 PID: 29481 Comm: sed Not tainted 5.13.0-514 #1'),
+ (OOMAnalyser.KernelConfig_5_8(), 'CPU: 4 PID: 29481 Comm: sed Not tainted 5.8.0-514 #1'),
+ (OOMAnalyser.KernelConfig_4_6(), 'CPU: 4 PID: 29481 Comm: sed Not tainted 4.6.0-514 #1'),
+ (OOMAnalyser.KernelConfigRhel7(), 'CPU: 4 PID: 29481 Comm: sed Not tainted 3.10.0-1062.9.1.el7.x86_64 #1'),
+ (OOMAnalyser.KernelConfig_5_0(), 'CPU: 4 PID: 29481 Comm: sed Not tainted 5.5.1 #1'),
+ (OOMAnalyser.KernelConfig_5_8(), 'CPU: 4 PID: 29481 Comm: sed Not tainted 5.23.0 #1'),
+ (OOMAnalyser.KernelConfig_5_8(), 'CPU: 4 PID: 29481 Comm: sed Not tainted 6.12.0 #1'),
+ (OOMAnalyser.BaseKernelConfig(), 'CPU: 4 PID: 29481 Comm: sed Not tainted 2.33.0 #1'),
+ ]:
+ oom = OOMAnalyser.OOMEntity(kversion)
+ analyser = OOMAnalyser.OOMAnalyser(oom)
+ analyser._identify_kernel_version()
+ analyser._choose_kernel_config()
+ result = analyser.oom_result.kconfig
+ self.assertEqual(
+ type(result), type(kcfg),
+ 'Mismatch between expected kernel config "%s" and chosen config "%s" for kernel version "%s"' % (
+ type(kcfg), type(result), kversion
+ )
+ )
+
if __name__ == "__main__":
unittest.main(verbosity=2)