diff options
Diffstat (limited to 'meta/lib/oeqa/utils/dump.py')
-rw-r--r-- | meta/lib/oeqa/utils/dump.py | 89 |
1 files changed, 66 insertions, 23 deletions
diff --git a/meta/lib/oeqa/utils/dump.py b/meta/lib/oeqa/utils/dump.py index 09a44329e0..d4d271369f 100644 --- a/meta/lib/oeqa/utils/dump.py +++ b/meta/lib/oeqa/utils/dump.py | |||
@@ -1,9 +1,12 @@ | |||
1 | # | 1 | # |
2 | # Copyright OpenEmbedded Contributors | ||
3 | # | ||
2 | # SPDX-License-Identifier: MIT | 4 | # SPDX-License-Identifier: MIT |
3 | # | 5 | # |
4 | 6 | ||
5 | import os | 7 | import os |
6 | import sys | 8 | import sys |
9 | import json | ||
7 | import errno | 10 | import errno |
8 | import datetime | 11 | import datetime |
9 | import itertools | 12 | import itertools |
@@ -17,6 +20,7 @@ class BaseDumper(object): | |||
17 | # Some testing doesn't inherit testimage, so it is needed | 20 | # Some testing doesn't inherit testimage, so it is needed |
18 | # to set some defaults. | 21 | # to set some defaults. |
19 | self.parent_dir = parent_dir | 22 | self.parent_dir = parent_dir |
23 | self.dump_dir = parent_dir | ||
20 | dft_cmds = """ top -bn1 | 24 | dft_cmds = """ top -bn1 |
21 | iostat -x -z -N -d -p ALL 20 2 | 25 | iostat -x -z -N -d -p ALL 20 2 |
22 | ps -ef | 26 | ps -ef |
@@ -46,11 +50,11 @@ class BaseDumper(object): | |||
46 | raise err | 50 | raise err |
47 | self.dump_dir = dump_dir | 51 | self.dump_dir = dump_dir |
48 | 52 | ||
49 | def _write_dump(self, command, output): | 53 | def _construct_filename(self, command): |
50 | if isinstance(self, HostDumper): | 54 | if isinstance(self, TargetDumper): |
51 | prefix = "host" | ||
52 | elif isinstance(self, TargetDumper): | ||
53 | prefix = "target" | 55 | prefix = "target" |
56 | elif isinstance(self, MonitorDumper): | ||
57 | prefix = "qmp" | ||
54 | else: | 58 | else: |
55 | prefix = "unknown" | 59 | prefix = "unknown" |
56 | for i in itertools.count(): | 60 | for i in itertools.count(): |
@@ -58,41 +62,80 @@ class BaseDumper(object): | |||
58 | fullname = os.path.join(self.dump_dir, filename) | 62 | fullname = os.path.join(self.dump_dir, filename) |
59 | if not os.path.exists(fullname): | 63 | if not os.path.exists(fullname): |
60 | break | 64 | break |
61 | with open(fullname, 'w') as dump_file: | 65 | return fullname |
62 | dump_file.write(output) | ||
63 | |||
64 | |||
65 | class HostDumper(BaseDumper): | ||
66 | """ Class to get dumps from the host running the tests """ | ||
67 | |||
68 | def __init__(self, cmds, parent_dir): | ||
69 | super(HostDumper, self).__init__(cmds, parent_dir) | ||
70 | 66 | ||
71 | def dump_host(self, dump_dir=""): | 67 | def _write_dump(self, command, output): |
72 | if dump_dir: | 68 | fullname = self._construct_filename(command) |
73 | self.dump_dir = dump_dir | 69 | os.makedirs(os.path.dirname(fullname), exist_ok=True) |
74 | env = os.environ.copy() | 70 | if isinstance(self, MonitorDumper): |
75 | env['PATH'] = '/usr/sbin:/sbin:/usr/bin:/bin' | 71 | with open(fullname, 'w') as json_file: |
76 | env['COLUMNS'] = '9999' | 72 | json.dump(output, json_file, indent=4) |
77 | for cmd in self.cmds: | 73 | else: |
78 | result = runCmd(cmd, ignore_status=True, env=env) | 74 | with open(fullname, 'w') as dump_file: |
79 | self._write_dump(cmd.split()[0], result.output) | 75 | dump_file.write(output) |
80 | 76 | ||
81 | class TargetDumper(BaseDumper): | 77 | class TargetDumper(BaseDumper): |
82 | """ Class to get dumps from target, it only works with QemuRunner """ | 78 | """ Class to get dumps from target, it only works with QemuRunner. |
79 | Will give up permanently after 5 errors from running commands over | ||
80 | serial console. This helps to end testing when target is really dead, hanging | ||
81 | or unresponsive. | ||
82 | """ | ||
83 | 83 | ||
84 | def __init__(self, cmds, parent_dir, runner): | 84 | def __init__(self, cmds, parent_dir, runner): |
85 | super(TargetDumper, self).__init__(cmds, parent_dir) | 85 | super(TargetDumper, self).__init__(cmds, parent_dir) |
86 | self.runner = runner | 86 | self.runner = runner |
87 | self.errors = 0 | ||
87 | 88 | ||
88 | def dump_target(self, dump_dir=""): | 89 | def dump_target(self, dump_dir=""): |
90 | if self.errors >= 5: | ||
91 | print("Too many errors when dumping data from target, assuming it is dead! Will not dump data anymore!") | ||
92 | return | ||
89 | if dump_dir: | 93 | if dump_dir: |
90 | self.dump_dir = dump_dir | 94 | self.dump_dir = dump_dir |
91 | for cmd in self.cmds: | 95 | for cmd in self.cmds: |
92 | # We can continue with the testing if serial commands fail | 96 | # We can continue with the testing if serial commands fail |
93 | try: | 97 | try: |
94 | (status, output) = self.runner.run_serial(cmd) | 98 | (status, output) = self.runner.run_serial(cmd) |
99 | if status == 0: | ||
100 | self.errors = self.errors + 1 | ||
95 | self._write_dump(cmd.split()[0], output) | 101 | self._write_dump(cmd.split()[0], output) |
96 | except: | 102 | except: |
103 | self.errors = self.errors + 1 | ||
97 | print("Tried to dump info from target but " | 104 | print("Tried to dump info from target but " |
98 | "serial console failed") | 105 | "serial console failed") |
106 | print("Failed CMD: %s" % (cmd)) | ||
107 | |||
108 | class MonitorDumper(BaseDumper): | ||
109 | """ Class to get dumps via the Qemu Monitor, it only works with QemuRunner | ||
110 | Will stop completely if there are more than 5 errors when dumping monitor data. | ||
111 | This helps to end testing when target is really dead, hanging or unresponsive. | ||
112 | """ | ||
113 | |||
114 | def __init__(self, cmds, parent_dir, runner): | ||
115 | super(MonitorDumper, self).__init__(cmds, parent_dir) | ||
116 | self.runner = runner | ||
117 | self.errors = 0 | ||
118 | |||
119 | def dump_monitor(self, dump_dir=""): | ||
120 | if self.runner is None: | ||
121 | return | ||
122 | if dump_dir: | ||
123 | self.dump_dir = dump_dir | ||
124 | if self.errors >= 5: | ||
125 | print("Too many errors when dumping data from qemu monitor, assuming it is dead! Will not dump data anymore!") | ||
126 | return | ||
127 | for cmd in self.cmds: | ||
128 | cmd_name = cmd.split()[0] | ||
129 | try: | ||
130 | if len(cmd.split()) > 1: | ||
131 | cmd_args = cmd.split()[1] | ||
132 | if "%s" in cmd_args: | ||
133 | filename = self._construct_filename(cmd_name) | ||
134 | cmd_data = json.loads(cmd_args % (filename)) | ||
135 | output = self.runner.run_monitor(cmd_name, cmd_data) | ||
136 | else: | ||
137 | output = self.runner.run_monitor(cmd_name) | ||
138 | self._write_dump(cmd_name, output) | ||
139 | except Exception as e: | ||
140 | self.errors = self.errors + 1 | ||
141 | print("Failed to dump QMP CMD: %s with\nException: %s" % (cmd_name, e)) | ||