Skip to content

Commit cb8a359

Browse files
authored
enable result retrieval for Sonobuoy (#937)
resolves #887 Signed-off-by: Matthias Büchse <[email protected]>
1 parent bb74a7c commit cb8a359

File tree

3 files changed

+38
-39
lines changed

3 files changed

+38
-39
lines changed

Tests/kaas/requirements.in

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,4 +3,3 @@ pytest-kind
33
kubernetes
44
kubernetes_asyncio
55
jinja2
6-
junitparser

Tests/kaas/requirements.txt

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -48,8 +48,6 @@ idna==3.10
4848
# yarl
4949
jinja2==3.1.6
5050
# via -r requirements.in
51-
junitparser==3.2.0
52-
# via -r requirements.in
5351
kubernetes==32.0.1
5452
# via -r requirements.in
5553
kubernetes-asyncio==32.3.2

Tests/kaas/sonobuoy_handler/sonobuoy_handler.py

Lines changed: 38 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
import shutil
88
import subprocess
99

10-
from junitparser import JUnitXml
10+
import yaml
1111

1212
logger = logging.getLogger(__name__)
1313

@@ -17,9 +17,15 @@ def _find_sonobuoy():
1717
result = shutil.which('sonobuoy')
1818
if result:
1919
return result
20+
logger.debug('sonobuoy not in PATH, trying $HOME/.local/bin')
2021
result = os.path.join(os.path.expanduser('~'), '.local', 'bin', 'sonobuoy')
2122
if os.path.exists(result):
2223
return result
24+
logger.debug('sonobuoy executable not found; expect errors')
25+
26+
27+
def _fmt_result(counter):
28+
return ', '.join(f"{counter.get(key, 0)} {key}" for key in ('passed', 'failed', 'skipped'))
2329

2430

2531
class SonobuoyHandler:
@@ -68,15 +74,14 @@ def _sonobuoy_status_result(self):
6874
json_data = json.loads(process.stdout)
6975
counter = Counter()
7076
for entry in json_data["plugins"]:
71-
logger.debug(f"plugin:{entry['plugin']}:{entry['result-status']}")
72-
for result, count in entry["result-counts"].items():
73-
counter[result] += count
77+
logger.debug(f"plugin {entry['plugin']}: {_fmt_result(entry['result-counts'])}")
78+
for key, value in entry["result-counts"].items():
79+
counter[key] += value
7480
return counter
7581

7682
def _eval_result(self, counter):
7783
"""evaluate test results and return return code"""
78-
result_str = ', '.join(f"{counter[key]} {key}" for key in ('passed', 'failed', 'skipped'))
79-
result_message = f"sonobuoy reports {result_str}"
84+
result_message = f"sonobuoy reports {_fmt_result(counter)}"
8085
if counter['failed']:
8186
logger.error(result_message)
8287
return 3
@@ -90,37 +95,33 @@ def _preflight_check(self):
9095
if not self.sonobuoy:
9196
raise RuntimeError("sonobuoy executable not found; is it in PATH?")
9297

93-
def _sonobuoy_retrieve_result(self):
98+
def _sonobuoy_retrieve_result(self, plugin='e2e'):
9499
"""
95-
This method invokes sonobuoy to store the results in a subdirectory of
96-
the working directory. The Junit results file contained in it is then
97-
analyzed in order to interpret the relevant information it containes
100+
Invoke sonobuoy to retrieve results and to store them in a subdirectory of
101+
the working directory. Analyze the results yaml file for given `plugin` and
102+
log each failure as ERROR. Return summary dict like `_sonobuoy_status_result`.
98103
"""
99104
logger.debug(f"retrieving results to {self.result_dir_name}")
100105
result_dir = os.path.join(self.working_directory, self.result_dir_name)
101-
if os.path.exists(result_dir):
102-
raise Exception("result directory already existing")
103-
os.mkdir(result_dir)
104-
105-
# XXX use self._invoke_sonobuoy
106-
os.system(
107-
# ~ f"sonobuoy retrieve {result_dir} -x --filename='{result_dir}' --kubeconfig='{self.kubeconfig_path}'"
108-
f"sonobuoy retrieve {result_dir} --kubeconfig='{self.kubeconfig_path}'"
109-
)
110-
logger.debug(
111-
f"parsing JUnit result from {result_dir + '/plugins/e2e/results/global/junit_01.xml'} "
112-
)
113-
xml = JUnitXml.fromfile(result_dir + "/plugins/e2e/results/global/junit_01.xml")
106+
os.makedirs(result_dir, exist_ok=True)
107+
108+
self._invoke_sonobuoy("retrieve", "-x", result_dir)
109+
yaml_path = os.path.join(result_dir, 'plugins', plugin, 'sonobuoy_results.yaml')
110+
logger.debug(f"parsing results from {yaml_path}")
111+
with open(yaml_path, "r") as fileobj:
112+
result_obj = yaml.load(fileobj.read(), yaml.SafeLoader)
114113
counter = Counter()
115-
for suite in xml:
116-
for case in suite:
117-
if case.is_passed is True: # XXX why `is True`???
118-
counter['passed'] += 1
119-
elif case.is_skipped is True:
120-
counter['skipped'] += 1
121-
else:
122-
counter['failed'] += 1
123-
logger.error(f"{case.name}")
114+
for item1 in result_obj.get('items', ()):
115+
# file ...
116+
for item2 in item1.get('items', ()):
117+
# suite ...
118+
for item in item2.get('items', ()):
119+
# testcase ... or so
120+
status = item.get('status', 'skipped')
121+
counter[status] += 1
122+
if status == 'failed':
123+
logger.error(f"FAILED: {item['name']}") # <-- this is why this method exists!
124+
logger.info(f"{plugin} results: {_fmt_result(counter)}")
124125
return counter
125126

126127
def run(self):
@@ -133,11 +134,12 @@ def run(self):
133134
self._sonobuoy_run()
134135
return_code = self._eval_result(self._sonobuoy_status_result())
135136
print(self.check_name + ": " + ("PASS", "FAIL")[min(1, return_code)])
137+
try:
138+
self._sonobuoy_retrieve_result()
139+
except Exception:
140+
# swallow exception for the time being
141+
logger.debug('problem retrieving results', exc_info=True)
136142
return return_code
137-
138-
# ERROR: currently disabled due to: "error retrieving results: unexpected EOF"
139-
# might be related to following bug: https://github.com/vmware-tanzu/sonobuoy/issues/1633
140-
# self._sonobuoy_retrieve_result(self)
141143
except BaseException:
142144
logger.exception("something went wrong")
143145
return 112

0 commit comments

Comments
 (0)